about summary refs log tree commit diff
path: root/tests/codegen-llvm
diff options
context:
space:
mode:
authorGuillaume Gomez <guillaume1.gomez@gmail.com>2025-07-21 14:34:12 +0200
committerGuillaume Gomez <guillaume1.gomez@gmail.com>2025-07-22 14:28:48 +0200
commita27f3e3fd1e4d16160f8885b6b06665b5319f56c (patch)
treeb033935392cbadf6f85d2dbddf433a88e323aeeb /tests/codegen-llvm
parented93c1783b404d728d4809973a0550eb33cd293f (diff)
downloadrust-a27f3e3fd1e4d16160f8885b6b06665b5319f56c.tar.gz
rust-a27f3e3fd1e4d16160f8885b6b06665b5319f56c.zip
Rename `tests/codegen` into `tests/codegen-llvm`
Diffstat (limited to 'tests/codegen-llvm')
-rw-r--r--tests/codegen-llvm/README.md24
-rw-r--r--tests/codegen-llvm/aarch64-softfloat.rs45
-rw-r--r--tests/codegen-llvm/aarch64-struct-align-128.rs145
-rw-r--r--tests/codegen-llvm/abi-efiapi.rs30
-rw-r--r--tests/codegen-llvm/abi-main-signature-16bit-c-int.rs11
-rw-r--r--tests/codegen-llvm/abi-main-signature-32bit-c-int.rs11
-rw-r--r--tests/codegen-llvm/abi-repr-ext.rs56
-rw-r--r--tests/codegen-llvm/abi-sysv64.rs20
-rw-r--r--tests/codegen-llvm/abi-win64-zst.rs54
-rw-r--r--tests/codegen-llvm/abi-x86-interrupt.rs18
-rw-r--r--tests/codegen-llvm/abi-x86-sse.rs43
-rw-r--r--tests/codegen-llvm/abi-x86_64_sysv.rs29
-rw-r--r--tests/codegen-llvm/addr-of-mutate.rs33
-rw-r--r--tests/codegen-llvm/adjustments.rs28
-rw-r--r--tests/codegen-llvm/align-byval-alignment-mismatch.rs126
-rw-r--r--tests/codegen-llvm/align-byval-vector.rs55
-rw-r--r--tests/codegen-llvm/align-byval.rs315
-rw-r--r--tests/codegen-llvm/align-enum.rs33
-rw-r--r--tests/codegen-llvm/align-fn.rs143
-rw-r--r--tests/codegen-llvm/align-offset.rs75
-rw-r--r--tests/codegen-llvm/align-struct.rs70
-rw-r--r--tests/codegen-llvm/alloc-optimisation.rs13
-rw-r--r--tests/codegen-llvm/amdgpu-addrspacecast.rs18
-rw-r--r--tests/codegen-llvm/array-clone.rs15
-rw-r--r--tests/codegen-llvm/array-cmp.rs74
-rw-r--r--tests/codegen-llvm/array-codegen.rs62
-rw-r--r--tests/codegen-llvm/array-equality.rs101
-rw-r--r--tests/codegen-llvm/array-from_fn.rs13
-rw-r--r--tests/codegen-llvm/array-map.rs35
-rw-r--r--tests/codegen-llvm/array-optimized.rs33
-rw-r--r--tests/codegen-llvm/array-repeat.rs15
-rw-r--r--tests/codegen-llvm/ascii-char.rs36
-rw-r--r--tests/codegen-llvm/asm/aarch64-clobbers.rs47
-rw-r--r--tests/codegen-llvm/asm/avr-clobbers.rs39
-rw-r--r--tests/codegen-llvm/asm/bpf-clobbers.rs31
-rw-r--r--tests/codegen-llvm/asm/critical.rs36
-rw-r--r--tests/codegen-llvm/asm/csky-clobbers.rs24
-rw-r--r--tests/codegen-llvm/asm/foo.s3
-rw-r--r--tests/codegen-llvm/asm/global_asm.rs28
-rw-r--r--tests/codegen-llvm/asm/global_asm_include.rs21
-rw-r--r--tests/codegen-llvm/asm/global_asm_x2.rs47
-rw-r--r--tests/codegen-llvm/asm/goto.rs63
-rw-r--r--tests/codegen-llvm/asm/hexagon-clobbers.rs33
-rw-r--r--tests/codegen-llvm/asm/may_unwind.rs39
-rw-r--r--tests/codegen-llvm/asm/maybe-uninit.rs27
-rw-r--r--tests/codegen-llvm/asm/msp430-clobbers.rs32
-rw-r--r--tests/codegen-llvm/asm/multiple-options.rs54
-rw-r--r--tests/codegen-llvm/asm/options.rs104
-rw-r--r--tests/codegen-llvm/asm/powerpc-clobbers.rs68
-rw-r--r--tests/codegen-llvm/asm/riscv-clobbers.rs40
-rw-r--r--tests/codegen-llvm/asm/s390x-clobbers.rs46
-rw-r--r--tests/codegen-llvm/asm/sanitize-llvm.rs24
-rw-r--r--tests/codegen-llvm/asm/sparc-clobbers.rs36
-rw-r--r--tests/codegen-llvm/asm/x86-clobber_abi.rs36
-rw-r--r--tests/codegen-llvm/asm/x86-clobbers.rs20
-rw-r--r--tests/codegen-llvm/asm/x86-target-clobbers.rs29
-rw-r--r--tests/codegen-llvm/assign-desugar-debuginfo.rs18
-rw-r--r--tests/codegen-llvm/async-closure-debug.rs20
-rw-r--r--tests/codegen-llvm/async-fn-debug-awaitee-field.rs28
-rw-r--r--tests/codegen-llvm/async-fn-debug-msvc.rs55
-rw-r--r--tests/codegen-llvm/async-fn-debug.rs59
-rw-r--r--tests/codegen-llvm/atomic-operations.rs84
-rw-r--r--tests/codegen-llvm/atomicptr.rs36
-rw-r--r--tests/codegen-llvm/autodiff/batched.rs116
-rw-r--r--tests/codegen-llvm/autodiff/generic.rs42
-rw-r--r--tests/codegen-llvm/autodiff/identical_fnc.rs45
-rw-r--r--tests/codegen-llvm/autodiff/inline.rs23
-rw-r--r--tests/codegen-llvm/autodiff/scalar.rs33
-rw-r--r--tests/codegen-llvm/autodiff/sret.rs45
-rw-r--r--tests/codegen-llvm/autodiffv2.rs113
-rw-r--r--tests/codegen-llvm/autovec/dont-shuffle-bswaps-opt2.rs31
-rw-r--r--tests/codegen-llvm/autovec/dont-shuffle-bswaps-opt3.rs42
-rw-r--r--tests/codegen-llvm/autovectorize-f32x4.rs37
-rw-r--r--tests/codegen-llvm/auxiliary/extern_decl.rs13
-rw-r--r--tests/codegen-llvm/auxiliary/nounwind.rs2
-rw-r--r--tests/codegen-llvm/auxiliary/thread_local_aux.rs5
-rw-r--r--tests/codegen-llvm/avr/avr-func-addrspace.rs106
-rw-r--r--tests/codegen-llvm/bigint-helpers.rs13
-rw-r--r--tests/codegen-llvm/binary-heap-peek-mut-pop-no-panic.rs13
-rw-r--r--tests/codegen-llvm/binary-search-index-no-bound-check.rs35
-rw-r--r--tests/codegen-llvm/bool-cmp.rs18
-rw-r--r--tests/codegen-llvm/bounds-checking/gep-issue-133979.rs22
-rw-r--r--tests/codegen-llvm/box-default-debug-copies.rs28
-rw-r--r--tests/codegen-llvm/box-uninit-bytes.rs46
-rw-r--r--tests/codegen-llvm/bpf-alu32.rs11
-rw-r--r--tests/codegen-llvm/branch-protection.rs94
-rw-r--r--tests/codegen-llvm/call-llvm-intrinsics.rs30
-rw-r--r--tests/codegen-llvm/call-tmps-lifetime.rs68
-rw-r--r--tests/codegen-llvm/cast-optimized.rs33
-rw-r--r--tests/codegen-llvm/cast-target-abi.rs599
-rw-r--r--tests/codegen-llvm/catch-unwind.rs32
-rw-r--r--tests/codegen-llvm/cdylib-external-inline-fns.rs43
-rw-r--r--tests/codegen-llvm/cf-protection.rs38
-rw-r--r--tests/codegen-llvm/cffi/c-variadic-copy.rs16
-rw-r--r--tests/codegen-llvm/cffi/c-variadic-naked.rs15
-rw-r--r--tests/codegen-llvm/cffi/c-variadic-opt.rs30
-rw-r--r--tests/codegen-llvm/cffi/c-variadic.rs71
-rw-r--r--tests/codegen-llvm/cffi/ffi-const.rs15
-rw-r--r--tests/codegen-llvm/cffi/ffi-out-of-bounds-loads.rs41
-rw-r--r--tests/codegen-llvm/cffi/ffi-pure.rs15
-rw-r--r--tests/codegen-llvm/cfguard-checks.rs10
-rw-r--r--tests/codegen-llvm/cfguard-disabled.rs10
-rw-r--r--tests/codegen-llvm/cfguard-nochecks.rs10
-rw-r--r--tests/codegen-llvm/cfguard-non-msvc.rs10
-rw-r--r--tests/codegen-llvm/char-ascii-branchless.rs47
-rw-r--r--tests/codegen-llvm/char-escape-debug-no-bounds-check.rs14
-rw-r--r--tests/codegen-llvm/checked_ilog.rs20
-rw-r--r--tests/codegen-llvm/checked_math.rs100
-rw-r--r--tests/codegen-llvm/clone-shims.rs15
-rw-r--r--tests/codegen-llvm/clone_as_copy.rs40
-rw-r--r--tests/codegen-llvm/codemodels.rs20
-rw-r--r--tests/codegen-llvm/coercions.rs19
-rw-r--r--tests/codegen-llvm/cold-call-declare-and-call.rs27
-rw-r--r--tests/codegen-llvm/common_prim_int_ptr.rs51
-rw-r--r--tests/codegen-llvm/comparison-operators-2-struct.rs61
-rw-r--r--tests/codegen-llvm/comparison-operators-2-tuple.rs117
-rw-r--r--tests/codegen-llvm/comparison-operators-newtype.rs48
-rw-r--r--tests/codegen-llvm/compiletest-self-test/minicore-smoke-test.rs20
-rw-r--r--tests/codegen-llvm/const-array.rs15
-rw-r--r--tests/codegen-llvm/const-vector.rs78
-rw-r--r--tests/codegen-llvm/const_scalar_pair.rs8
-rw-r--r--tests/codegen-llvm/constant-branch.rs49
-rw-r--r--tests/codegen-llvm/consts.rs55
-rw-r--r--tests/codegen-llvm/coroutine-debug-msvc.rs60
-rw-r--r--tests/codegen-llvm/coroutine-debug.rs64
-rw-r--r--tests/codegen-llvm/cross-crate-inlining/always-inline.rs13
-rw-r--r--tests/codegen-llvm/cross-crate-inlining/auxiliary/always.rs20
-rw-r--r--tests/codegen-llvm/cross-crate-inlining/auxiliary/leaf.rs20
-rw-r--r--tests/codegen-llvm/cross-crate-inlining/auxiliary/never.rs20
-rw-r--r--tests/codegen-llvm/cross-crate-inlining/leaf-inlining.rs20
-rw-r--r--tests/codegen-llvm/cross-crate-inlining/never-inline.rs13
-rw-r--r--tests/codegen-llvm/dealloc-no-unwind.rs25
-rw-r--r--tests/codegen-llvm/debug-accessibility/crate-enum.rs28
-rw-r--r--tests/codegen-llvm/debug-accessibility/crate-struct.rs23
-rw-r--r--tests/codegen-llvm/debug-accessibility/private-enum.rs22
-rw-r--r--tests/codegen-llvm/debug-accessibility/private-struct.rs17
-rw-r--r--tests/codegen-llvm/debug-accessibility/public-enum.rs23
-rw-r--r--tests/codegen-llvm/debug-accessibility/public-struct.rs17
-rw-r--r--tests/codegen-llvm/debug-accessibility/struct-fields.rs30
-rw-r--r--tests/codegen-llvm/debug-accessibility/super-enum.rs28
-rw-r--r--tests/codegen-llvm/debug-accessibility/super-struct.rs23
-rw-r--r--tests/codegen-llvm/debug-accessibility/tuple-fields.rs24
-rw-r--r--tests/codegen-llvm/debug-alignment.rs8
-rw-r--r--tests/codegen-llvm/debug-column-msvc.rs16
-rw-r--r--tests/codegen-llvm/debug-column.rs25
-rw-r--r--tests/codegen-llvm/debug-compile-unit-path.rs9
-rw-r--r--tests/codegen-llvm/debug-fndef-size.rs20
-rw-r--r--tests/codegen-llvm/debug-limited.rs27
-rw-r--r--tests/codegen-llvm/debug-line-directives-only.rs27
-rw-r--r--tests/codegen-llvm/debug-line-tables-only.rs27
-rw-r--r--tests/codegen-llvm/debug-linkage-name.rs42
-rw-r--r--tests/codegen-llvm/debug-vtable.rs117
-rw-r--r--tests/codegen-llvm/debuginfo-constant-locals.rs28
-rw-r--r--tests/codegen-llvm/debuginfo-generic-closure-env-names.rs90
-rw-r--r--tests/codegen-llvm/debuginfo-inline-callsite-location.rs27
-rw-r--r--tests/codegen-llvm/debuginfo-proc-macro/auxiliary/macro_def.rs7
-rw-r--r--tests/codegen-llvm/debuginfo-proc-macro/mir_inlined_twice_var_locs.rs52
-rw-r--r--tests/codegen-llvm/deduced-param-attrs.rs60
-rw-r--r--tests/codegen-llvm/default-requires-uwtable.rs17
-rw-r--r--tests/codegen-llvm/default-visibility.rs49
-rw-r--r--tests/codegen-llvm/direct-access-external-data.rs21
-rw-r--r--tests/codegen-llvm/dllimports/auxiliary/dummy.rs6
-rw-r--r--tests/codegen-llvm/dllimports/auxiliary/wrapper.rs14
-rw-r--r--tests/codegen-llvm/dllimports/main.rs43
-rw-r--r--tests/codegen-llvm/dont_codegen_private_const_fn_only_used_in_const_eval.rs27
-rw-r--r--tests/codegen-llvm/drop-in-place-noalias.rs38
-rw-r--r--tests/codegen-llvm/drop.rs36
-rw-r--r--tests/codegen-llvm/dst-offset.rs84
-rw-r--r--tests/codegen-llvm/dst-vtable-align-nonzero.rs67
-rw-r--r--tests/codegen-llvm/dst-vtable-size-range.rs35
-rw-r--r--tests/codegen-llvm/ehcontguard_disabled.rs9
-rw-r--r--tests/codegen-llvm/ehcontguard_enabled.rs9
-rw-r--r--tests/codegen-llvm/emscripten-catch-unwind-js-eh.rs71
-rw-r--r--tests/codegen-llvm/emscripten-catch-unwind-wasm-eh.rs69
-rw-r--r--tests/codegen-llvm/enable-lto-unit-splitting.rs9
-rw-r--r--tests/codegen-llvm/enum/enum-aggregate.rs126
-rw-r--r--tests/codegen-llvm/enum/enum-bounds-check-derived-idx.rs24
-rw-r--r--tests/codegen-llvm/enum/enum-bounds-check-issue-13926.rs18
-rw-r--r--tests/codegen-llvm/enum/enum-bounds-check-issue-82871.rs18
-rw-r--r--tests/codegen-llvm/enum/enum-bounds-check.rs27
-rw-r--r--tests/codegen-llvm/enum/enum-debug-clike.rs28
-rw-r--r--tests/codegen-llvm/enum/enum-debug-niche-2.rs47
-rw-r--r--tests/codegen-llvm/enum/enum-debug-niche.rs35
-rw-r--r--tests/codegen-llvm/enum/enum-debug-tagged.rs31
-rw-r--r--tests/codegen-llvm/enum/enum-discriminant-eq.rs223
-rw-r--r--tests/codegen-llvm/enum/enum-discriminant-value.rs27
-rw-r--r--tests/codegen-llvm/enum/enum-early-otherwise-branch.rs25
-rw-r--r--tests/codegen-llvm/enum/enum-match.rs779
-rw-r--r--tests/codegen-llvm/enum/enum-two-variants-match.rs130
-rw-r--r--tests/codegen-llvm/enum/enum-u128.rs25
-rw-r--r--tests/codegen-llvm/enum/unreachable_enum_default_branch.rs40
-rw-r--r--tests/codegen-llvm/ergonomic-clones/closure.rs55
-rw-r--r--tests/codegen-llvm/error-provide.rs50
-rw-r--r--tests/codegen-llvm/export-no-mangle.rs31
-rw-r--r--tests/codegen-llvm/external-no-mangle-fns.rs75
-rw-r--r--tests/codegen-llvm/external-no-mangle-statics.rs77
-rw-r--r--tests/codegen-llvm/f128-wasm32-callconv.rs49
-rw-r--r--tests/codegen-llvm/fastcall-inreg.rs40
-rw-r--r--tests/codegen-llvm/fatptr.rs12
-rw-r--r--tests/codegen-llvm/fewer-names.rs19
-rw-r--r--tests/codegen-llvm/fixed-x18.rs23
-rw-r--r--tests/codegen-llvm/float/algebraic.rs149
-rw-r--r--tests/codegen-llvm/float/f128.rs441
-rw-r--r--tests/codegen-llvm/float/f16-f128-inline.rs29
-rw-r--r--tests/codegen-llvm/float/f16.rs364
-rw-r--r--tests/codegen-llvm/float_math.rs87
-rw-r--r--tests/codegen-llvm/fn-impl-trait-self.rs17
-rw-r--r--tests/codegen-llvm/fn-parameters-on-different-lines-debuginfo.rs22
-rw-r--r--tests/codegen-llvm/force-frame-pointers.rs18
-rw-r--r--tests/codegen-llvm/force-no-unwind-tables.rs11
-rw-r--r--tests/codegen-llvm/force-unwind-tables.rs6
-rw-r--r--tests/codegen-llvm/frame-pointer-cli-control.rs61
-rw-r--r--tests/codegen-llvm/frame-pointer.rs35
-rw-r--r--tests/codegen-llvm/function-arguments-noopt.rs69
-rw-r--r--tests/codegen-llvm/function-arguments.rs278
-rw-r--r--tests/codegen-llvm/function-return.rs35
-rw-r--r--tests/codegen-llvm/gdb_debug_script_load.rs37
-rw-r--r--tests/codegen-llvm/generic-debug.rs17
-rw-r--r--tests/codegen-llvm/gep-index.rs37
-rw-r--r--tests/codegen-llvm/gpu-kernel-abi.rs15
-rw-r--r--tests/codegen-llvm/gpu_offload/gpu_host.rs80
-rw-r--r--tests/codegen-llvm/hint/cold_path.rs54
-rw-r--r--tests/codegen-llvm/hint/likely.rs81
-rw-r--r--tests/codegen-llvm/hint/unlikely.rs80
-rw-r--r--tests/codegen-llvm/i128-wasm32-callconv.rs49
-rw-r--r--tests/codegen-llvm/i128-x86-align.rs105
-rw-r--r--tests/codegen-llvm/i128-x86-callconv.rs87
-rw-r--r--tests/codegen-llvm/infallible-unwrap-in-opt-z.rs26
-rw-r--r--tests/codegen-llvm/inherit_overflow.rs14
-rw-r--r--tests/codegen-llvm/inline-always-works-always.rs21
-rw-r--r--tests/codegen-llvm/inline-debuginfo.rs17
-rw-r--r--tests/codegen-llvm/inline-function-args-debug-info.rs23
-rw-r--r--tests/codegen-llvm/inline-hint.rs31
-rw-r--r--tests/codegen-llvm/instrument-coverage/instrument-coverage-off.rs21
-rw-r--r--tests/codegen-llvm/instrument-coverage/instrument-coverage.rs22
-rw-r--r--tests/codegen-llvm/instrument-coverage/testprog.rs118
-rw-r--r--tests/codegen-llvm/instrument-mcount.rs7
-rw-r--r--tests/codegen-llvm/instrument-xray/basic.rs9
-rw-r--r--tests/codegen-llvm/instrument-xray/options-combine.rs12
-rw-r--r--tests/codegen-llvm/instrument-xray/options-override.rs11
-rw-r--r--tests/codegen-llvm/integer-cmp.rs62
-rw-r--r--tests/codegen-llvm/integer-overflow.rs24
-rw-r--r--tests/codegen-llvm/internalize-closures.rs13
-rw-r--r--tests/codegen-llvm/intrinsic-no-unnamed-attr.rs13
-rw-r--r--tests/codegen-llvm/intrinsics/aggregate-thin-pointer.rs23
-rw-r--r--tests/codegen-llvm/intrinsics/carrying_mul_add.rs136
-rw-r--r--tests/codegen-llvm/intrinsics/cold_path.rs13
-rw-r--r--tests/codegen-llvm/intrinsics/cold_path2.rs37
-rw-r--r--tests/codegen-llvm/intrinsics/cold_path3.rs87
-rw-r--r--tests/codegen-llvm/intrinsics/compare_bytes.rs34
-rw-r--r--tests/codegen-llvm/intrinsics/const_eval_select.rs22
-rw-r--r--tests/codegen-llvm/intrinsics/ctlz.rs56
-rw-r--r--tests/codegen-llvm/intrinsics/ctpop.rs31
-rw-r--r--tests/codegen-llvm/intrinsics/disjoint_bitor.rs30
-rw-r--r--tests/codegen-llvm/intrinsics/exact_div.rs20
-rw-r--r--tests/codegen-llvm/intrinsics/likely.rs35
-rw-r--r--tests/codegen-llvm/intrinsics/likely_assert.rs17
-rw-r--r--tests/codegen-llvm/intrinsics/mask.rs12
-rw-r--r--tests/codegen-llvm/intrinsics/nontemporal.rs32
-rw-r--r--tests/codegen-llvm/intrinsics/offset.rs33
-rw-r--r--tests/codegen-llvm/intrinsics/offset_from.rs36
-rw-r--r--tests/codegen-llvm/intrinsics/prefetch.rs64
-rw-r--r--tests/codegen-llvm/intrinsics/ptr_metadata.rs36
-rw-r--r--tests/codegen-llvm/intrinsics/rotate_left.rs31
-rw-r--r--tests/codegen-llvm/intrinsics/rustc_intrinsic_must_be_overridden.rs14
-rw-r--r--tests/codegen-llvm/intrinsics/select_unpredictable.rs71
-rw-r--r--tests/codegen-llvm/intrinsics/three_way_compare.rs28
-rw-r--r--tests/codegen-llvm/intrinsics/transmute-niched.rs223
-rw-r--r--tests/codegen-llvm/intrinsics/transmute-x64.rs28
-rw-r--r--tests/codegen-llvm/intrinsics/transmute.rs497
-rw-r--r--tests/codegen-llvm/intrinsics/typed_swap.rs77
-rw-r--r--tests/codegen-llvm/intrinsics/unchecked_math.rs46
-rw-r--r--tests/codegen-llvm/intrinsics/unlikely.rs35
-rw-r--r--tests/codegen-llvm/intrinsics/volatile.rs55
-rw-r--r--tests/codegen-llvm/intrinsics/volatile_order.rs18
-rw-r--r--tests/codegen-llvm/is_val_statically_known.rs163
-rw-r--r--tests/codegen-llvm/issue-97217.rs20
-rw-r--r--tests/codegen-llvm/issues/issue-101048.rs12
-rw-r--r--tests/codegen-llvm/issues/issue-101082.rs42
-rw-r--r--tests/codegen-llvm/issues/issue-101814.rs18
-rw-r--r--tests/codegen-llvm/issues/issue-103132.rs15
-rw-r--r--tests/codegen-llvm/issues/issue-103285-ptr-addr-overflow-check.rs15
-rw-r--r--tests/codegen-llvm/issues/issue-103327.rs13
-rw-r--r--tests/codegen-llvm/issues/issue-103840.rs9
-rw-r--r--tests/codegen-llvm/issues/issue-105386-ub-in-debuginfo.rs24
-rw-r--r--tests/codegen-llvm/issues/issue-106369.rs14
-rw-r--r--tests/codegen-llvm/issues/issue-107681-unwrap_unchecked.rs19
-rw-r--r--tests/codegen-llvm/issues/issue-108395-branchy-bool-match.rs27
-rw-r--r--tests/codegen-llvm/issues/issue-109328-split_first.rs16
-rw-r--r--tests/codegen-llvm/issues/issue-110797-enum-jump-same.rs25
-rw-r--r--tests/codegen-llvm/issues/issue-111603.rs40
-rw-r--r--tests/codegen-llvm/issues/issue-112509-slice-get-andthen-get.rs16
-rw-r--r--tests/codegen-llvm/issues/issue-113757-bounds-check-after-cmp-max.rs18
-rw-r--r--tests/codegen-llvm/issues/issue-114312.rs25
-rw-r--r--tests/codegen-llvm/issues/issue-115385-llvm-jump-threading.rs46
-rw-r--r--tests/codegen-llvm/issues/issue-116878.rs11
-rw-r--r--tests/codegen-llvm/issues/issue-118306.rs22
-rw-r--r--tests/codegen-llvm/issues/issue-118392.rs10
-rw-r--r--tests/codegen-llvm/issues/issue-119422.rs83
-rw-r--r--tests/codegen-llvm/issues/issue-121719-common-field-offset.rs44
-rw-r--r--tests/codegen-llvm/issues/issue-122600-ptr-discriminant-update.rs43
-rw-r--r--tests/codegen-llvm/issues/issue-123712-str-to-lower-autovectorization.rs23
-rw-r--r--tests/codegen-llvm/issues/issue-126585.rs23
-rw-r--r--tests/codegen-llvm/issues/issue-129795.rs17
-rw-r--r--tests/codegen-llvm/issues/issue-13018.rs14
-rw-r--r--tests/codegen-llvm/issues/issue-136329-optnone-noinline.rs21
-rw-r--r--tests/codegen-llvm/issues/issue-15953.rs29
-rw-r--r--tests/codegen-llvm/issues/issue-27130.rs21
-rw-r--r--tests/codegen-llvm/issues/issue-32031.rs29
-rw-r--r--tests/codegen-llvm/issues/issue-32364.rs17
-rw-r--r--tests/codegen-llvm/issues/issue-34634.rs16
-rw-r--r--tests/codegen-llvm/issues/issue-34947-pow-i32.rs13
-rw-r--r--tests/codegen-llvm/issues/issue-36010-some-box-is_some.rs28
-rw-r--r--tests/codegen-llvm/issues/issue-37945.rs34
-rw-r--r--tests/codegen-llvm/issues/issue-45222.rs62
-rw-r--r--tests/codegen-llvm/issues/issue-45466.rs14
-rw-r--r--tests/codegen-llvm/issues/issue-45964-bounds-check-slice-pos.rs38
-rw-r--r--tests/codegen-llvm/issues/issue-47278.rs11
-rw-r--r--tests/codegen-llvm/issues/issue-47442.rs22
-rw-r--r--tests/codegen-llvm/issues/issue-56267-2.rs18
-rw-r--r--tests/codegen-llvm/issues/issue-56267.rs18
-rw-r--r--tests/codegen-llvm/issues/issue-56927.rs46
-rw-r--r--tests/codegen-llvm/issues/issue-58881.rs20
-rw-r--r--tests/codegen-llvm/issues/issue-59352.rs18
-rw-r--r--tests/codegen-llvm/issues/issue-64219-fn-ptr-call-returning-never-is-noreturn.rs19
-rw-r--r--tests/codegen-llvm/issues/issue-68667-unwrap-combinators.rs15
-rw-r--r--tests/codegen-llvm/issues/issue-69101-bounds-check.rs42
-rw-r--r--tests/codegen-llvm/issues/issue-73031.rs22
-rw-r--r--tests/codegen-llvm/issues/issue-73258.rs40
-rw-r--r--tests/codegen-llvm/issues/issue-73338-effecient-cmp.rs39
-rw-r--r--tests/codegen-llvm/issues/issue-73396-bounds-check-after-position.rs70
-rw-r--r--tests/codegen-llvm/issues/issue-73827-bounds-check-index-in-subexpr.rs17
-rw-r--r--tests/codegen-llvm/issues/issue-74938-array-split-at.rs14
-rw-r--r--tests/codegen-llvm/issues/issue-75525-bounds-checks.rs26
-rw-r--r--tests/codegen-llvm/issues/issue-75546.rs17
-rw-r--r--tests/codegen-llvm/issues/issue-75659.rs63
-rw-r--r--tests/codegen-llvm/issues/issue-75978.rs18
-rw-r--r--tests/codegen-llvm/issues/issue-77812.rs32
-rw-r--r--tests/codegen-llvm/issues/issue-84268.rs18
-rw-r--r--tests/codegen-llvm/issues/issue-85872-multiple-reverse.rs19
-rw-r--r--tests/codegen-llvm/issues/issue-86106.rs63
-rw-r--r--tests/codegen-llvm/issues/issue-86109-eliminate-div-by-zero-check.rs26
-rw-r--r--tests/codegen-llvm/issues/issue-93036-assert-index.rs14
-rw-r--r--tests/codegen-llvm/issues/issue-96274.rs15
-rw-r--r--tests/codegen-llvm/issues/issue-96497-slice-size-nowrap.rs38
-rw-r--r--tests/codegen-llvm/issues/issue-98294-get-mut-copy-from-slice-opt.rs17
-rw-r--r--tests/codegen-llvm/issues/issue-98678-async.rs27
-rw-r--r--tests/codegen-llvm/issues/issue-98678-closure-coroutine.rs25
-rw-r--r--tests/codegen-llvm/issues/issue-98678-enum.rs42
-rw-r--r--tests/codegen-llvm/issues/issue-98678-struct-union.rs27
-rw-r--r--tests/codegen-llvm/issues/issue-99960.rs10
-rw-r--r--tests/codegen-llvm/issues/looping-over-ne-bytes-133528.rs17
-rw-r--r--tests/codegen-llvm/issues/str-to-string-128690.rs38
-rw-r--r--tests/codegen-llvm/iter-repeat-n-trivial-drop.rs70
-rw-r--r--tests/codegen-llvm/layout-size-checks.rs30
-rw-r--r--tests/codegen-llvm/lib-optimizations/iter-sum.rs13
-rw-r--r--tests/codegen-llvm/lib-optimizations/slice_rotate.rs30
-rw-r--r--tests/codegen-llvm/lifetime_start_end.rs34
-rw-r--r--tests/codegen-llvm/link-dead-code.rs28
-rw-r--r--tests/codegen-llvm/link_section.rs35
-rw-r--r--tests/codegen-llvm/llvm-ident.rs15
-rw-r--r--tests/codegen-llvm/llvm_module_flags.rs7
-rw-r--r--tests/codegen-llvm/loads.rs152
-rw-r--r--tests/codegen-llvm/local-generics-in-exe-internalized.rs14
-rw-r--r--tests/codegen-llvm/loongarch-abi/call-llvm-intrinsics.rs31
-rw-r--r--tests/codegen-llvm/loongarch-abi/loongarch64-lp64d-abi.rs299
-rw-r--r--tests/codegen-llvm/lto-removes-invokes.rs21
-rw-r--r--tests/codegen-llvm/macos/i686-macosx-deployment-target.rs23
-rw-r--r--tests/codegen-llvm/macos/i686-no-macosx-deployment-target.rs23
-rw-r--r--tests/codegen-llvm/macos/x86_64-macosx-deployment-target.rs23
-rw-r--r--tests/codegen-llvm/macos/x86_64-no-macosx-deployment-target.rs23
-rw-r--r--tests/codegen-llvm/mainsubprogram.rs12
-rw-r--r--tests/codegen-llvm/match-optimized.rs60
-rw-r--r--tests/codegen-llvm/match-optimizes-away.rs41
-rw-r--r--tests/codegen-llvm/match-unoptimized.rs23
-rw-r--r--tests/codegen-llvm/maybeuninit-rvo.rs34
-rw-r--r--tests/codegen-llvm/mem-replace-big-type.rs36
-rw-r--r--tests/codegen-llvm/mem-replace-simple-type.rs54
-rw-r--r--tests/codegen-llvm/merge-functions.rs16
-rw-r--r--tests/codegen-llvm/meta-filecheck/check-prefix.rs4
-rw-r--r--tests/codegen-llvm/meta-filecheck/filecheck-flags.rs8
-rw-r--r--tests/codegen-llvm/meta-filecheck/msvc-prefix-bad.rs7
-rw-r--r--tests/codegen-llvm/meta-filecheck/no-directives.rs5
-rw-r--r--tests/codegen-llvm/meta-filecheck/revision-prefix.rs8
-rw-r--r--tests/codegen-llvm/method-declaration.rs26
-rw-r--r--tests/codegen-llvm/min-function-alignment.rs48
-rw-r--r--tests/codegen-llvm/mir-aggregate-no-alloca.rs137
-rw-r--r--tests/codegen-llvm/mir-inlined-line-numbers.rs25
-rw-r--r--tests/codegen-llvm/mir_zst_stores.rs19
-rw-r--r--tests/codegen-llvm/move-before-nocapture-ref-arg.rs21
-rw-r--r--tests/codegen-llvm/move-operands.rs13
-rw-r--r--tests/codegen-llvm/naked-asan.rs30
-rw-r--r--tests/codegen-llvm/naked-fn/aligned.rs21
-rw-r--r--tests/codegen-llvm/naked-fn/generics.rs111
-rw-r--r--tests/codegen-llvm/naked-fn/instruction-set.rs53
-rw-r--r--tests/codegen-llvm/naked-fn/min-function-alignment.rs47
-rw-r--r--tests/codegen-llvm/naked-fn/naked-functions.rs165
-rw-r--r--tests/codegen-llvm/no-alloca-inside-if-false.rs27
-rw-r--r--tests/codegen-llvm/no-assumes-on-casts.rs19
-rw-r--r--tests/codegen-llvm/no-dllimport-w-cross-lang-lto.rs13
-rw-r--r--tests/codegen-llvm/no-jump-tables.rs23
-rw-r--r--tests/codegen-llvm/no-plt.rs17
-rw-r--r--tests/codegen-llvm/no-redundant-item-monomorphization.rs33
-rw-r--r--tests/codegen-llvm/no_builtins-at-crate.rs24
-rw-r--r--tests/codegen-llvm/noalias-box-off.rs11
-rw-r--r--tests/codegen-llvm/noalias-box.rs8
-rw-r--r--tests/codegen-llvm/noalias-flag.rs23
-rw-r--r--tests/codegen-llvm/noalias-freeze.rs23
-rw-r--r--tests/codegen-llvm/noalias-refcell.rs14
-rw-r--r--tests/codegen-llvm/noalias-rwlockreadguard.rs14
-rw-r--r--tests/codegen-llvm/noalias-unpin.rs15
-rw-r--r--tests/codegen-llvm/non-terminate/infinite-loop-1.rs17
-rw-r--r--tests/codegen-llvm/non-terminate/infinite-loop-2.rs19
-rw-r--r--tests/codegen-llvm/non-terminate/infinite-recursion.rs13
-rw-r--r--tests/codegen-llvm/non-terminate/nonempty-infinite-loop.rs28
-rw-r--r--tests/codegen-llvm/noreturn-uninhabited.rs31
-rw-r--r--tests/codegen-llvm/noreturnflag.rs22
-rw-r--r--tests/codegen-llvm/nounwind.rs15
-rw-r--r--tests/codegen-llvm/nrvo.rs17
-rw-r--r--tests/codegen-llvm/optimize-attr-1.rs59
-rw-r--r--tests/codegen-llvm/option-as-slice.rs71
-rw-r--r--tests/codegen-llvm/option-niche-eq.rs87
-rw-r--r--tests/codegen-llvm/option-niche-unfixed/option-nonzero-eq.rs24
-rw-r--r--tests/codegen-llvm/overaligned-constant.rs35
-rw-r--r--tests/codegen-llvm/packed.rs153
-rw-r--r--tests/codegen-llvm/panic-abort-windows.rs16
-rw-r--r--tests/codegen-llvm/panic-in-drop-abort.rs57
-rw-r--r--tests/codegen-llvm/panic-unwind-default-uwtable.rs6
-rw-r--r--tests/codegen-llvm/patchable-function-entry/patchable-function-entry-both-flags.rs64
-rw-r--r--tests/codegen-llvm/patchable-function-entry/patchable-function-entry-no-flag.rs39
-rw-r--r--tests/codegen-llvm/patchable-function-entry/patchable-function-entry-one-flag.rs66
-rw-r--r--tests/codegen-llvm/pattern_type_symbols.rs22
-rw-r--r--tests/codegen-llvm/personality_lifetimes.rs32
-rw-r--r--tests/codegen-llvm/pgo-counter-bias.rs10
-rw-r--r--tests/codegen-llvm/pgo-instrumentation.rs20
-rw-r--r--tests/codegen-llvm/pic-relocation-model.rs19
-rw-r--r--tests/codegen-llvm/pie-relocation-model.rs22
-rw-r--r--tests/codegen-llvm/placement-new.rs39
-rw-r--r--tests/codegen-llvm/powerpc64le-struct-align-128.rs96
-rw-r--r--tests/codegen-llvm/precondition-checks.rs25
-rw-r--r--tests/codegen-llvm/ptr-arithmetic.rs33
-rw-r--r--tests/codegen-llvm/ptr-read-metadata.rs94
-rw-r--r--tests/codegen-llvm/range-attribute.rs74
-rw-r--r--tests/codegen-llvm/range-loop.rs44
-rw-r--r--tests/codegen-llvm/range_to_inclusive.rs28
-rw-r--r--tests/codegen-llvm/refs.rs21
-rw-r--r--tests/codegen-llvm/reg-struct-return.rs206
-rw-r--r--tests/codegen-llvm/regparm-inreg.rs125
-rw-r--r--tests/codegen-llvm/remap_path_prefix/aux_mod.rs6
-rw-r--r--tests/codegen-llvm/remap_path_prefix/auxiliary/remap_path_prefix_aux.rs8
-rw-r--r--tests/codegen-llvm/remap_path_prefix/auxiliary/xcrate-generic.rs8
-rw-r--r--tests/codegen-llvm/remap_path_prefix/issue-73167-remap-std.rs15
-rw-r--r--tests/codegen-llvm/remap_path_prefix/main.rs28
-rw-r--r--tests/codegen-llvm/remap_path_prefix/xcrate-generic.rs14
-rw-r--r--tests/codegen-llvm/repeat-operand-zero-len.rs28
-rw-r--r--tests/codegen-llvm/repeat-operand-zst-elem.rs28
-rw-r--r--tests/codegen-llvm/repeat-trusted-len.rs20
-rw-r--r--tests/codegen-llvm/repr/transparent-byval-struct-ptr.rs111
-rw-r--r--tests/codegen-llvm/repr/transparent-imm-array.rs116
-rw-r--r--tests/codegen-llvm/repr/transparent-mips64.rs103
-rw-r--r--tests/codegen-llvm/repr/transparent-opaque-ptr.rs109
-rw-r--r--tests/codegen-llvm/repr/transparent-sparc64.rs113
-rw-r--r--tests/codegen-llvm/repr/transparent-sysv64.rs49
-rw-r--r--tests/codegen-llvm/repr/transparent.rs221
-rw-r--r--tests/codegen-llvm/retpoline.rs27
-rw-r--r--tests/codegen-llvm/riscv-abi/call-llvm-intrinsics.rs30
-rw-r--r--tests/codegen-llvm/riscv-abi/cast-local-large-enough.rs44
-rw-r--r--tests/codegen-llvm/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs176
-rw-r--r--tests/codegen-llvm/riscv-abi/riscv64-lp64d-abi.rs299
-rw-r--r--tests/codegen-llvm/riscv-abi/riscv64-lp64f-lp64d-abi.rs283
-rw-r--r--tests/codegen-llvm/riscv-target-abi.rs21
-rw-r--r--tests/codegen-llvm/rust-abi-arch-specific-adjustment.rs111
-rw-r--r--tests/codegen-llvm/s390x-simd.rs143
-rw-r--r--tests/codegen-llvm/sanitizer/aarch64-shadow-call-stack-with-fixed-x18.rs20
-rw-r--r--tests/codegen-llvm/sanitizer/address-sanitizer-globals-tracking.rs44
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/add-canonical-jump-tables-flag.rs10
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/add-cfi-normalize-integers-flag.rs10
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/add-enable-split-lto-unit-flag.rs10
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/dbg-location-on-cfi-blocks.rs19
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-checks-attr-no-sanitize.rs18
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-checks.rs19
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-attr-cfi-encoding.rs73
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-const-generics.rs32
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-drop-in-place.rs31
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-function-types.rs45
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-lifetimes.rs29
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-method-secondary-typeid.rs21
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs86
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-pointer-types.rs54
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-primitive-types.rs190
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-repr-transparent-types.rs79
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-sequence-types.rs36
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-trait-types.rs175
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-user-defined-types.rs62
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-generalized.rs31
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized-generalized.rs31
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized.rs31
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi.rs31
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-trait-objects.rs145
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/external_weak_symbols.rs24
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/generalize-pointers.rs46
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/normalize-integers.rs46
-rw-r--r--tests/codegen-llvm/sanitizer/dataflow-instrument-functions.rs9
-rw-r--r--tests/codegen-llvm/sanitizer/kasan-emits-instrumentation.rs41
-rw-r--r--tests/codegen-llvm/sanitizer/kcfi/add-cfi-normalize-integers-flag.rs20
-rw-r--r--tests/codegen-llvm/sanitizer/kcfi/add-kcfi-arity-flag.rs19
-rw-r--r--tests/codegen-llvm/sanitizer/kcfi/add-kcfi-flag.rs20
-rw-r--r--tests/codegen-llvm/sanitizer/kcfi/add-kcfi-offset-flag.rs20
-rw-r--r--tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-attr-no-sanitize.rs27
-rw-r--r--tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-generalized.rs41
-rw-r--r--tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-normalized-generalized.rs41
-rw-r--r--tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-normalized.rs41
-rw-r--r--tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi.rs41
-rw-r--r--tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle.rs24
-rw-r--r--tests/codegen-llvm/sanitizer/kcfi/emit-type-metadata-trait-objects.rs155
-rw-r--r--tests/codegen-llvm/sanitizer/kcfi/naked-function.rs47
-rw-r--r--tests/codegen-llvm/sanitizer/memory-track-origins.rs31
-rw-r--r--tests/codegen-llvm/sanitizer/memtag-attr-check.rs12
-rw-r--r--tests/codegen-llvm/sanitizer/no-sanitize-inlining.rs31
-rw-r--r--tests/codegen-llvm/sanitizer/no-sanitize.rs39
-rw-r--r--tests/codegen-llvm/sanitizer/riscv64-shadow-call-stack.rs18
-rw-r--r--tests/codegen-llvm/sanitizer/safestack-attr-check.rs11
-rw-r--r--tests/codegen-llvm/sanitizer/sanitizer-recover.rs50
-rw-r--r--tests/codegen-llvm/sanitizer/scs-attr-check.rs17
-rw-r--r--tests/codegen-llvm/scalar-pair-bool.rs45
-rw-r--r--tests/codegen-llvm/set-discriminant-invalid.rs34
-rw-r--r--tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-abs.rs60
-rw-r--r--tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-ceil.rs60
-rw-r--r--tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-cos.rs60
-rw-r--r--tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-exp.rs60
-rw-r--r--tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-exp2.rs60
-rw-r--r--tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-floor.rs60
-rw-r--r--tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-fma.rs60
-rw-r--r--tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-fsqrt.rs60
-rw-r--r--tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-log.rs60
-rw-r--r--tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-log10.rs60
-rw-r--r--tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-log2.rs60
-rw-r--r--tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-minmax.rs25
-rw-r--r--tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-sin.rs60
-rw-r--r--tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.rs579
-rw-r--r--tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-bitmask.rs48
-rw-r--r--tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-gather.rs55
-rw-r--r--tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-masked-load.rs49
-rw-r--r--tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-masked-store.rs41
-rw-r--r--tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-scatter.rs47
-rw-r--r--tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-select.rs48
-rw-r--r--tests/codegen-llvm/simd-intrinsic/simd-intrinsic-mask-reduce.rs60
-rw-r--r--tests/codegen-llvm/simd-intrinsic/simd-intrinsic-transmute-array.rs58
-rw-r--r--tests/codegen-llvm/simd/aggregate-simd.rs102
-rw-r--r--tests/codegen-llvm/simd/extract-insert-dyn.rs121
-rw-r--r--tests/codegen-llvm/simd/packed-simd-alignment.rs44
-rw-r--r--tests/codegen-llvm/simd/packed-simd.rs56
-rw-r--r--tests/codegen-llvm/simd/simd-wide-sum.rs59
-rw-r--r--tests/codegen-llvm/simd/simd_arith_offset.rs22
-rw-r--r--tests/codegen-llvm/simd/swap-simd-types.rs40
-rw-r--r--tests/codegen-llvm/simd/unpadded-simd.rs19
-rw-r--r--tests/codegen-llvm/skip-mono-inside-if-false.rs41
-rw-r--r--tests/codegen-llvm/slice-as_chunks.rs30
-rw-r--r--tests/codegen-llvm/slice-indexing.rs99
-rw-r--r--tests/codegen-llvm/slice-init.rs108
-rw-r--r--tests/codegen-llvm/slice-is-ascii.rs16
-rw-r--r--tests/codegen-llvm/slice-iter-fold.rs12
-rw-r--r--tests/codegen-llvm/slice-iter-len-eq-zero.rs60
-rw-r--r--tests/codegen-llvm/slice-iter-nonnull.rs115
-rw-r--r--tests/codegen-llvm/slice-last-elements-optimization.rs37
-rw-r--r--tests/codegen-llvm/slice-pointer-nonnull-unwrap.rs18
-rw-r--r--tests/codegen-llvm/slice-position-bounds-check.rs25
-rw-r--r--tests/codegen-llvm/slice-ref-equality.rs90
-rw-r--r--tests/codegen-llvm/slice-reverse.rs27
-rw-r--r--tests/codegen-llvm/slice-split-at.rs24
-rw-r--r--tests/codegen-llvm/slice-windows-no-bounds-check.rs32
-rw-r--r--tests/codegen-llvm/slice_as_from_ptr_range.rs21
-rw-r--r--tests/codegen-llvm/some-abis-do-extend-params-to-32-bits.rs236
-rw-r--r--tests/codegen-llvm/some-global-nonnull.rs25
-rw-r--r--tests/codegen-llvm/sparc-struct-abi.rs97
-rw-r--r--tests/codegen-llvm/split-lto-unit.rs10
-rw-r--r--tests/codegen-llvm/src-hash-algorithm/src-hash-algorithm-md5.rs6
-rw-r--r--tests/codegen-llvm/src-hash-algorithm/src-hash-algorithm-sha1.rs6
-rw-r--r--tests/codegen-llvm/src-hash-algorithm/src-hash-algorithm-sha256.rs6
-rw-r--r--tests/codegen-llvm/sroa-fragment-debuginfo.rs46
-rw-r--r--tests/codegen-llvm/sse42-implies-crc32.rs15
-rw-r--r--tests/codegen-llvm/stack-probes-inline.rs33
-rw-r--r--tests/codegen-llvm/stack-protector.rs34
-rw-r--r--tests/codegen-llvm/static-relocation-model-msvc.rs24
-rw-r--r--tests/codegen-llvm/staticlib-external-inline-fns.rs43
-rw-r--r--tests/codegen-llvm/step_by-overflow-checks.rs26
-rw-r--r--tests/codegen-llvm/stores.rs35
-rw-r--r--tests/codegen-llvm/string-push.rs11
-rw-r--r--tests/codegen-llvm/swap-large-types.rs116
-rw-r--r--tests/codegen-llvm/swap-small-types.rs182
-rw-r--r--tests/codegen-llvm/target-cpu-on-functions.rs22
-rw-r--r--tests/codegen-llvm/target-feature-inline-closure.rs33
-rw-r--r--tests/codegen-llvm/target-feature-negative-implication.rs20
-rw-r--r--tests/codegen-llvm/target-feature-overrides.rs46
-rw-r--r--tests/codegen-llvm/terminating-catchpad.rs43
-rw-r--r--tests/codegen-llvm/thread-local.rs54
-rw-r--r--tests/codegen-llvm/tied-features-strength.rs34
-rw-r--r--tests/codegen-llvm/to_vec.rs10
-rw-r--r--tests/codegen-llvm/trailing_zeros.rs21
-rw-r--r--tests/codegen-llvm/transmute-optimized.rs120
-rw-r--r--tests/codegen-llvm/transmute-scalar.rs143
-rw-r--r--tests/codegen-llvm/try_question_mark_nop.rs243
-rw-r--r--tests/codegen-llvm/tune-cpu-on-functions.rs21
-rw-r--r--tests/codegen-llvm/tuple-layout-opt.rs57
-rw-r--r--tests/codegen-llvm/ub-checks.rs28
-rw-r--r--tests/codegen-llvm/unchecked-float-casts.rs36
-rw-r--r--tests/codegen-llvm/unchecked_shifts.rs100
-rw-r--r--tests/codegen-llvm/uninhabited-transparent-return-abi.rs44
-rw-r--r--tests/codegen-llvm/uninit-consts.rs54
-rw-r--r--tests/codegen-llvm/uninit-repeat-in-aggregate.rs21
-rw-r--r--tests/codegen-llvm/union-abi.rs145
-rw-r--r--tests/codegen-llvm/union-aggregate.rs108
-rw-r--r--tests/codegen-llvm/unwind-abis/aapcs-unwind-abi.rs36
-rw-r--r--tests/codegen-llvm/unwind-abis/c-unwind-abi-panic-abort.rs27
-rw-r--r--tests/codegen-llvm/unwind-abis/c-unwind-abi.rs27
-rw-r--r--tests/codegen-llvm/unwind-abis/cdecl-unwind-abi.rs27
-rw-r--r--tests/codegen-llvm/unwind-abis/fastcall-unwind-abi.rs36
-rw-r--r--tests/codegen-llvm/unwind-abis/nounwind-on-stable-panic-abort.rs15
-rw-r--r--tests/codegen-llvm/unwind-abis/nounwind.rs16
-rw-r--r--tests/codegen-llvm/unwind-abis/stdcall-unwind-abi.rs36
-rw-r--r--tests/codegen-llvm/unwind-abis/system-unwind-abi.rs27
-rw-r--r--tests/codegen-llvm/unwind-abis/sysv64-unwind-abi.rs36
-rw-r--r--tests/codegen-llvm/unwind-abis/thiscall-unwind-abi.rs36
-rw-r--r--tests/codegen-llvm/unwind-abis/vectorcall-unwind-abi.rs36
-rw-r--r--tests/codegen-llvm/unwind-abis/win64-unwind-abi.rs36
-rw-r--r--tests/codegen-llvm/unwind-and-panic-abort.rs16
-rw-r--r--tests/codegen-llvm/unwind-extern-exports.rs15
-rw-r--r--tests/codegen-llvm/unwind-extern-imports.rs21
-rw-r--r--tests/codegen-llvm/unwind-landingpad-cold.rs15
-rw-r--r--tests/codegen-llvm/unwind-landingpad-inline.rs39
-rw-r--r--tests/codegen-llvm/used_with_arg.rs10
-rw-r--r--tests/codegen-llvm/var-names.rs15
-rw-r--r--tests/codegen-llvm/vec-as-ptr.rs19
-rw-r--r--tests/codegen-llvm/vec-calloc.rs182
-rw-r--r--tests/codegen-llvm/vec-in-place.rs161
-rw-r--r--tests/codegen-llvm/vec-iter-collect-len.rs12
-rw-r--r--tests/codegen-llvm/vec-iter.rs58
-rw-r--r--tests/codegen-llvm/vec-len-invariant.rs16
-rw-r--r--tests/codegen-llvm/vec-optimizes-away.rs12
-rw-r--r--tests/codegen-llvm/vec-reserve-extend.rs14
-rw-r--r--tests/codegen-llvm/vec-shrink-panik.rs31
-rw-r--r--tests/codegen-llvm/vec-with-capacity.rs35
-rw-r--r--tests/codegen-llvm/vec_pop_push_noop.rs24
-rw-r--r--tests/codegen-llvm/vecdeque-drain.rs70
-rw-r--r--tests/codegen-llvm/vecdeque-nonempty-get-no-panic.rs16
-rw-r--r--tests/codegen-llvm/vecdeque_no_panic.rs19
-rw-r--r--tests/codegen-llvm/vecdeque_pop_push.rs67
-rw-r--r--tests/codegen-llvm/virtual-call-attrs-issue-137646.rs37
-rw-r--r--tests/codegen-llvm/virtual-function-elimination-32bit.rs35
-rw-r--r--tests/codegen-llvm/virtual-function-elimination.rs98
-rw-r--r--tests/codegen-llvm/vtable-loads.rs16
-rw-r--r--tests/codegen-llvm/vtable-upcast.rs84
-rw-r--r--tests/codegen-llvm/wasm_casts_trapping.rs157
-rw-r--r--tests/codegen-llvm/wasm_exceptions.rs59
-rw-r--r--tests/codegen-llvm/zip.rs21
-rw-r--r--tests/codegen-llvm/zst-offset.rs42
656 files changed, 31706 insertions, 0 deletions
diff --git a/tests/codegen-llvm/README.md b/tests/codegen-llvm/README.md
new file mode 100644
index 00000000000..8f2daaafcc7
--- /dev/null
+++ b/tests/codegen-llvm/README.md
@@ -0,0 +1,24 @@
+The files here use the LLVM FileCheck framework, documented at
+<https://llvm.org/docs/CommandGuide/FileCheck.html>.
+
+One extension worth noting is the use of revisions as custom prefixes for
+FileCheck. If your codegen test has different behavior based on the chosen
+target or different compiler flags that you want to exercise, you can use a
+revisions annotation, like so:
+
+```rust
+// revisions: aaa bbb
+// [bbb] compile-flags: --flags-for-bbb
+```
+
+After specifying those variations, you can write different expected, or
+explicitly *unexpected* output by using `<prefix>-SAME:` and `<prefix>-NOT:`,
+like so:
+
+```rust
+// CHECK: expected code
+// aaa-SAME: emitted-only-for-aaa
+// aaa-NOT:                        emitted-only-for-bbb
+// bbb-NOT:  emitted-only-for-aaa
+// bbb-SAME:                       emitted-only-for-bbb
+```
diff --git a/tests/codegen-llvm/aarch64-softfloat.rs b/tests/codegen-llvm/aarch64-softfloat.rs
new file mode 100644
index 00000000000..4f5366e047f
--- /dev/null
+++ b/tests/codegen-llvm/aarch64-softfloat.rs
@@ -0,0 +1,45 @@
+//@ add-core-stubs
+//@ compile-flags: --target aarch64-unknown-none-softfloat -Zmerge-functions=disabled
+//@ needs-llvm-components: aarch64
+#![crate_type = "lib"]
+#![feature(no_core, lang_items)]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+// CHECK: i64 @pass_f64_C(i64 {{[^,]*}})
+#[no_mangle]
+extern "C" fn pass_f64_C(x: f64) -> f64 {
+    x
+}
+
+// CHECK: i64 @pass_f32_pair_C(i64 {{[^,]*}})
+#[no_mangle]
+extern "C" fn pass_f32_pair_C(x: (f32, f32)) -> (f32, f32) {
+    x
+}
+
+// CHECK: [2 x i64] @pass_f64_pair_C([2 x i64] {{[^,]*}})
+#[no_mangle]
+extern "C" fn pass_f64_pair_C(x: (f64, f64)) -> (f64, f64) {
+    x
+}
+
+// CHECK: i64 @pass_f64_Rust(i64 {{[^,]*}})
+#[no_mangle]
+fn pass_f64_Rust(x: f64) -> f64 {
+    x
+}
+
+// CHECK: i64 @pass_f32_pair_Rust(i64 {{[^,]*}})
+#[no_mangle]
+fn pass_f32_pair_Rust(x: (f32, f32)) -> (f32, f32) {
+    x
+}
+
+// CHECK: void @pass_f64_pair_Rust(ptr {{.*}}%{{[^ ]+}}, ptr {{.*}}%{{[^ ]+}})
+#[no_mangle]
+fn pass_f64_pair_Rust(x: (f64, f64)) -> (f64, f64) {
+    x
+}
diff --git a/tests/codegen-llvm/aarch64-struct-align-128.rs b/tests/codegen-llvm/aarch64-struct-align-128.rs
new file mode 100644
index 00000000000..ba1d19680f4
--- /dev/null
+++ b/tests/codegen-llvm/aarch64-struct-align-128.rs
@@ -0,0 +1,145 @@
+// Test that structs aligned to 128 bits are passed with the correct ABI on aarch64.
+
+//@ add-core-stubs
+//@ revisions: linux darwin win
+//@[linux] compile-flags: --target aarch64-unknown-linux-gnu
+//@[darwin] compile-flags: --target aarch64-apple-darwin
+//@[win] compile-flags: --target aarch64-pc-windows-msvc
+//@[linux] needs-llvm-components: aarch64
+//@[darwin] needs-llvm-components: aarch64
+//@[win] needs-llvm-components: aarch64
+
+#![feature(no_core, lang_items)]
+#![crate_type = "lib"]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+// Passed as `[i64 x 2]`, since it's an aggregate with size <= 128 bits, align < 128 bits.
+#[repr(C)]
+pub struct Align8 {
+    pub a: u64,
+    pub b: u64,
+}
+
+// repr(transparent), so same as above.
+#[repr(transparent)]
+pub struct Transparent8 {
+    a: Align8,
+}
+
+// Passed as `[i64 x 2]`, since it's an aggregate with size <= 128 bits, align < 128 bits.
+#[repr(C)]
+pub struct Wrapped8 {
+    a: Align8,
+}
+
+extern "C" {
+    // linux:  declare void @test_8([2 x i64], [2 x i64], [2 x i64])
+    // darwin: declare void @test_8([2 x i64], [2 x i64], [2 x i64])
+    // win:    declare void @test_8([2 x i64], [2 x i64], [2 x i64])
+    fn test_8(a: Align8, b: Transparent8, c: Wrapped8);
+}
+
+// Passed as `i128`, since it's an aggregate with size <= 128 bits, align = 128 bits.
+// EXCEPT on Linux, where there's a special case to use its unadjusted alignment,
+// making it the same as `Align8`, so it's be passed as `[i64 x 2]`.
+#[repr(C)]
+#[repr(align(16))]
+pub struct Align16 {
+    pub a: u64,
+    pub b: u64,
+}
+
+// repr(transparent), so same as above.
+#[repr(transparent)]
+pub struct Transparent16 {
+    a: Align16,
+}
+
+// Passed as `i128`, since it's an aggregate with size <= 128 bits, align = 128 bits.
+// On Linux, the "unadjustedness" doesn't recurse into fields, so this is passed as `i128`.
+#[repr(C)]
+pub struct Wrapped16 {
+    pub a: Align16,
+}
+
+extern "C" {
+    // linux:  declare void @test_16([2 x i64], [2 x i64], i128)
+    // darwin: declare void @test_16(i128, i128, i128)
+    // win:    declare void @test_16(i128, i128, i128)
+    fn test_16(a: Align16, b: Transparent16, c: Wrapped16);
+}
+
+// Passed as `i128`, since it's an aggregate with size <= 128 bits, align = 128 bits.
+#[repr(C)]
+pub struct I128 {
+    pub a: i128,
+}
+
+// repr(transparent), so same as above.
+#[repr(transparent)]
+pub struct TransparentI128 {
+    a: I128,
+}
+
+// Passed as `i128`, since it's an aggregate with size <= 128 bits, align = 128 bits.
+#[repr(C)]
+pub struct WrappedI128 {
+    pub a: I128,
+}
+
+extern "C" {
+    // linux:  declare void @test_i128(i128, i128, i128)
+    // darwin: declare void @test_i128(i128, i128, i128)
+    // win:    declare void @test_i128(i128, i128, i128)
+    fn test_i128(a: I128, b: TransparentI128, c: WrappedI128);
+}
+
+// Passed as `[2 x i64]`, since it's an aggregate with size <= 128 bits, align < 128 bits.
+// Note that the Linux special case does not apply, because packing is not considered "adjustment".
+#[repr(C)]
+#[repr(packed)]
+pub struct Packed {
+    pub a: i128,
+}
+
+// repr(transparent), so same as above.
+#[repr(transparent)]
+pub struct TransparentPacked {
+    a: Packed,
+}
+
+// Passed as `[2 x i64]`, since it's an aggregate with size <= 128 bits, align < 128 bits.
+#[repr(C)]
+pub struct WrappedPacked {
+    pub a: Packed,
+}
+
+extern "C" {
+    // linux:  declare void @test_packed([2 x i64], [2 x i64], [2 x i64])
+    // darwin: declare void @test_packed([2 x i64], [2 x i64], [2 x i64])
+    // win:    declare void @test_packed([2 x i64], [2 x i64], [2 x i64])
+    fn test_packed(a: Packed, b: TransparentPacked, c: WrappedPacked);
+}
+
+pub unsafe fn main(
+    a1: Align8,
+    a2: Transparent8,
+    a3: Wrapped8,
+    b1: Align16,
+    b2: Transparent16,
+    b3: Wrapped16,
+    c1: I128,
+    c2: TransparentI128,
+    c3: WrappedI128,
+    d1: Packed,
+    d2: TransparentPacked,
+    d3: WrappedPacked,
+) {
+    test_8(a1, a2, a3);
+    test_16(b1, b2, b3);
+    test_i128(c1, c2, c3);
+    test_packed(d1, d2, d3);
+}
diff --git a/tests/codegen-llvm/abi-efiapi.rs b/tests/codegen-llvm/abi-efiapi.rs
new file mode 100644
index 00000000000..1736f0daf0f
--- /dev/null
+++ b/tests/codegen-llvm/abi-efiapi.rs
@@ -0,0 +1,30 @@
+// Checks if the correct annotation for the efiapi ABI is passed to llvm.
+
+//@ add-core-stubs
+//@ revisions:x86_64 i686 aarch64 arm riscv
+//@[x86_64] compile-flags: --target x86_64-unknown-uefi
+//@[x86_64] needs-llvm-components: aarch64 arm riscv
+//@[i686] compile-flags: --target i686-unknown-linux-musl
+//@[i686] needs-llvm-components: aarch64 arm riscv
+//@[aarch64] compile-flags: --target aarch64-unknown-none
+//@[aarch64] needs-llvm-components: aarch64 arm riscv
+//@[arm] compile-flags: --target armv7r-none-eabi
+//@[arm] needs-llvm-components: aarch64 arm riscv
+//@[riscv] compile-flags: --target riscv64gc-unknown-none-elf
+//@[riscv] needs-llvm-components: aarch64 arm riscv
+//@ compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+#![feature(no_core, lang_items)]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+//x86_64: define win64cc void @has_efiapi
+//i686: define void @has_efiapi
+//aarch64: define dso_local void @has_efiapi
+//arm: define dso_local arm_aapcscc void @has_efiapi
+//riscv: define dso_local void @has_efiapi
+#[no_mangle]
+pub extern "efiapi" fn has_efiapi() {}
diff --git a/tests/codegen-llvm/abi-main-signature-16bit-c-int.rs b/tests/codegen-llvm/abi-main-signature-16bit-c-int.rs
new file mode 100644
index 00000000000..d44b80475e4
--- /dev/null
+++ b/tests/codegen-llvm/abi-main-signature-16bit-c-int.rs
@@ -0,0 +1,11 @@
+// Checks the signature of the implicitly generated native main()
+// entry point. It must match C's `int main(int, char **)`.
+
+// This test is for targets with 16bit c_int only.
+//@ revisions: avr msp
+//@[avr] only-avr
+//@[msp] only-msp430
+
+fn main() {}
+
+// CHECK: define i16 @main(i16, i8**)
diff --git a/tests/codegen-llvm/abi-main-signature-32bit-c-int.rs b/tests/codegen-llvm/abi-main-signature-32bit-c-int.rs
new file mode 100644
index 00000000000..ce475adde44
--- /dev/null
+++ b/tests/codegen-llvm/abi-main-signature-32bit-c-int.rs
@@ -0,0 +1,11 @@
+// Checks the signature of the implicitly generated native main()
+// entry point. It must match C's `int main(int, char **)`.
+
+// This test is for targets with 32bit c_int only.
+//@ ignore-msp430
+//@ ignore-avr
+//@ ignore-wasi wasi codegens the main symbol differently
+
+fn main() {}
+
+// CHECK: define{{( hidden| noundef)*}} i32 @main(i32{{( %0)?}}, ptr{{( %1)?}})
diff --git a/tests/codegen-llvm/abi-repr-ext.rs b/tests/codegen-llvm/abi-repr-ext.rs
new file mode 100644
index 00000000000..1da28a94d9d
--- /dev/null
+++ b/tests/codegen-llvm/abi-repr-ext.rs
@@ -0,0 +1,56 @@
+//@ add-core-stubs
+//@ compile-flags: -Copt-level=3
+
+//@ revisions:x86_64 i686 aarch64-apple aarch64-windows aarch64-linux arm riscv
+
+//@[x86_64] compile-flags: --target x86_64-unknown-uefi
+//@[x86_64] needs-llvm-components: x86
+//@[i686] compile-flags: --target i686-unknown-linux-musl
+//@[i686] needs-llvm-components: x86
+//@[aarch64-windows] compile-flags: --target aarch64-pc-windows-msvc
+//@[aarch64-windows] needs-llvm-components: aarch64
+//@[aarch64-linux] compile-flags: --target aarch64-unknown-linux-gnu
+//@[aarch64-linux] needs-llvm-components: aarch64
+//@[aarch64-apple] compile-flags: --target aarch64-apple-darwin
+//@[aarch64-apple] needs-llvm-components: aarch64
+//@[arm] compile-flags: --target armv7r-none-eabi
+//@[arm] needs-llvm-components: arm
+//@[riscv] compile-flags: --target riscv64gc-unknown-none-elf
+//@[riscv] needs-llvm-components: riscv
+
+// See bottom of file for a corresponding C source file that is meant to yield
+// equivalent declarations.
+#![feature(no_core, lang_items)]
+#![crate_type = "lib"]
+#![no_std]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+#[repr(i8)]
+pub enum Type {
+    Type1 = 0,
+    Type2 = 1,
+}
+
+// To accommodate rust#97800, one might consider writing the below as:
+//
+// `define{{( dso_local)?}} noundef{{( signext)?}} i8 @test()`
+//
+// but based on rust#80556, it seems important to actually check for the
+// presence of the `signext` for those targets where we expect it.
+
+// CHECK: define{{( dso_local)?}} noundef
+// x86_64-SAME:                 signext
+// aarch64-apple-SAME:          signext
+// aarch64-windows-NOT: signext
+// aarch64-linux-NOT:   signext
+// arm-SAME:                    signext
+// riscv-SAME:                  signext
+// CHECK-SAME: i8 @test()
+
+#[no_mangle]
+pub extern "C" fn test() -> Type {
+    Type::Type1
+}
diff --git a/tests/codegen-llvm/abi-sysv64.rs b/tests/codegen-llvm/abi-sysv64.rs
new file mode 100644
index 00000000000..7ade17f2bae
--- /dev/null
+++ b/tests/codegen-llvm/abi-sysv64.rs
@@ -0,0 +1,20 @@
+// Checks if the correct annotation for the sysv64 ABI is passed to
+// llvm. Also checks that the abi-sysv64 feature gate allows usage
+// of the sysv64 abi.
+//
+//@ add-core-stubs
+//@ needs-llvm-components: x86
+//@ compile-flags: -C no-prepopulate-passes --target=x86_64-unknown-linux-gnu -Copt-level=0
+
+#![crate_type = "lib"]
+#![no_core]
+#![feature(abi_x86_interrupt, no_core, lang_items)]
+
+extern crate minicore;
+use minicore::*;
+
+// CHECK: define x86_64_sysvcc i64 @has_sysv64_abi
+#[no_mangle]
+pub extern "sysv64" fn has_sysv64_abi(a: i64) -> i64 {
+    a
+}
diff --git a/tests/codegen-llvm/abi-win64-zst.rs b/tests/codegen-llvm/abi-win64-zst.rs
new file mode 100644
index 00000000000..e46f9666d42
--- /dev/null
+++ b/tests/codegen-llvm/abi-win64-zst.rs
@@ -0,0 +1,54 @@
+//@ add-core-stubs
+//@ compile-flags: -Z merge-functions=disabled
+//@ add-core-stubs
+
+//@ revisions: windows-gnu
+//@[windows-gnu] compile-flags: --target x86_64-pc-windows-gnu
+//@[windows-gnu] needs-llvm-components: x86
+
+//@ revisions: windows-msvc
+//@[windows-msvc] compile-flags: --target x86_64-pc-windows-msvc
+//@[windows-msvc] needs-llvm-components: x86
+
+// Also test what happens when using a Windows ABI on Linux.
+//@ revisions: linux
+//@[linux] compile-flags: --target x86_64-unknown-linux-gnu
+//@[linux] needs-llvm-components: x86
+
+#![feature(no_core, rustc_attrs, abi_vectorcall)]
+#![no_core]
+#![crate_type = "lib"]
+
+extern crate minicore;
+use minicore::*;
+
+// Make sure the argument is always passed when explicitly requesting a Windows ABI.
+// Our goal here is to match clang: <https://clang.godbolt.org/z/Wr4jMWq3P>.
+
+// CHECK: define win64cc void @pass_zst_win64(ptr {{[^,]*}})
+#[no_mangle]
+extern "win64" fn pass_zst_win64(_: ()) {}
+
+// CHECK: define x86_vectorcallcc void @pass_zst_vectorcall(ptr {{[^,]*}})
+#[no_mangle]
+extern "vectorcall" fn pass_zst_vectorcall(_: ()) {}
+
+// windows-gnu: define void @pass_zst_fastcall(ptr {{[^,]*}})
+// windows-msvc: define void @pass_zst_fastcall(ptr {{[^,]*}})
+#[no_mangle]
+#[cfg(windows)] // "fastcall" is not valid on 64bit Linux
+extern "fastcall" fn pass_zst_fastcall(_: ()) {}
+
+// The sysv64 ABI ignores ZST.
+
+// CHECK: define x86_64_sysvcc void @pass_zst_sysv64()
+#[no_mangle]
+extern "sysv64" fn pass_zst_sysv64(_: ()) {}
+
+// For `extern "C"` functions, ZST are ignored on Linux put passed on Windows.
+
+// linux: define void @pass_zst_c()
+// windows-msvc: define void @pass_zst_c(ptr {{[^,]*}})
+// windows-gnu: define void @pass_zst_c(ptr {{[^,]*}})
+#[no_mangle]
+extern "C" fn pass_zst_c(_: ()) {}
diff --git a/tests/codegen-llvm/abi-x86-interrupt.rs b/tests/codegen-llvm/abi-x86-interrupt.rs
new file mode 100644
index 00000000000..9a1ded2c9e3
--- /dev/null
+++ b/tests/codegen-llvm/abi-x86-interrupt.rs
@@ -0,0 +1,18 @@
+// Checks if the correct annotation for the x86-interrupt ABI is passed to
+// llvm. Also checks that the abi_x86_interrupt feature gate allows usage
+// of the x86-interrupt abi.
+
+//@ add-core-stubs
+//@ needs-llvm-components: x86
+//@ compile-flags: -C no-prepopulate-passes --target=x86_64-unknown-linux-gnu -Copt-level=0
+
+#![crate_type = "lib"]
+#![no_core]
+#![feature(abi_x86_interrupt, no_core, lang_items)]
+
+extern crate minicore;
+use minicore::*;
+
+// CHECK: define x86_intrcc void @has_x86_interrupt_abi
+#[no_mangle]
+pub extern "x86-interrupt" fn has_x86_interrupt_abi() {}
diff --git a/tests/codegen-llvm/abi-x86-sse.rs b/tests/codegen-llvm/abi-x86-sse.rs
new file mode 100644
index 00000000000..68d2acfb527
--- /dev/null
+++ b/tests/codegen-llvm/abi-x86-sse.rs
@@ -0,0 +1,43 @@
+//@ compile-flags: -Z merge-functions=disabled
+
+//@ revisions: x86-64
+//@[x86-64] compile-flags: --target x86_64-unknown-linux-gnu
+//@[x86-64] needs-llvm-components: x86
+
+//@ revisions: x86-32
+//@[x86-32] compile-flags: --target i686-unknown-linux-gnu
+//@[x86-32] needs-llvm-components: x86
+
+//@ revisions: x86-32-nosse
+//@[x86-32-nosse] compile-flags: --target i586-unknown-linux-gnu
+//@[x86-32-nosse] needs-llvm-components: x86
+
+#![feature(no_core, lang_items, rustc_attrs, repr_simd)]
+#![no_core]
+#![crate_type = "lib"]
+
+#[lang = "sized"]
+trait Sized: MetaSized {}
+
+#[lang = "meta_sized"]
+trait MetaSized: PointeeSized {}
+
+#[lang = "pointee_sized"]
+trait PointeeSized {}
+
+#[lang = "copy"]
+trait Copy {}
+
+// Ensure this type is passed without ptr indirection on targets that
+// require SSE2.
+#[repr(simd)]
+pub struct Sse([f32; 4]);
+
+// FIXME: due to #139029 we are passing them all indirectly.
+// x86-64: void @sse_id(ptr{{( [^,]*)?}} sret([16 x i8]){{( .*)?}}, ptr{{( [^,]*)?}})
+// x86-32: void @sse_id(ptr{{( [^,]*)?}} sret([16 x i8]){{( .*)?}}, ptr{{( [^,]*)?}})
+// x86-32-nosse: void @sse_id(ptr{{( [^,]*)?}} sret([16 x i8]){{( .*)?}}, ptr{{( [^,]*)?}})
+#[no_mangle]
+pub fn sse_id(x: Sse) -> Sse {
+    x
+}
diff --git a/tests/codegen-llvm/abi-x86_64_sysv.rs b/tests/codegen-llvm/abi-x86_64_sysv.rs
new file mode 100644
index 00000000000..09909f994d6
--- /dev/null
+++ b/tests/codegen-llvm/abi-x86_64_sysv.rs
@@ -0,0 +1,29 @@
+//@ only-x86_64
+
+//@ compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+pub struct S24 {
+    a: i8,
+    b: i8,
+    c: i8,
+}
+
+pub struct S48 {
+    a: i16,
+    b: i16,
+    c: i8,
+}
+
+// CHECK: i24 @struct_24_bits(i24
+#[no_mangle]
+pub extern "sysv64" fn struct_24_bits(a: S24) -> S24 {
+    a
+}
+
+// CHECK: i48 @struct_48_bits(i48
+#[no_mangle]
+pub extern "sysv64" fn struct_48_bits(a: S48) -> S48 {
+    a
+}
diff --git a/tests/codegen-llvm/addr-of-mutate.rs b/tests/codegen-llvm/addr-of-mutate.rs
new file mode 100644
index 00000000000..14bc4b8ab28
--- /dev/null
+++ b/tests/codegen-llvm/addr-of-mutate.rs
@@ -0,0 +1,33 @@
+//@ compile-flags: -C opt-level=3 -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+// Test for the absence of `readonly` on the argument when it is mutated via `&raw const`.
+// See <https://github.com/rust-lang/rust/issues/111502>.
+
+// CHECK: i8 @foo(ptr noalias{{( nocapture)?}} noundef align 1{{( captures\(none\))?}} dereferenceable(128) %x)
+#[no_mangle]
+pub fn foo(x: [u8; 128]) -> u8 {
+    let ptr = core::ptr::addr_of!(x).cast_mut();
+    unsafe {
+        (*ptr)[0] = 1;
+    }
+    x[0]
+}
+
+// CHECK: i1 @second(ptr noalias{{( nocapture)?}} noundef align {{[0-9]+}}{{( captures\(none\))?}} dereferenceable({{[0-9]+}}) %a_ptr_and_b)
+#[no_mangle]
+pub unsafe fn second(a_ptr_and_b: (*mut (i32, bool), (i64, bool))) -> bool {
+    let b_bool_ptr = core::ptr::addr_of!(a_ptr_and_b.1.1).cast_mut();
+    (*b_bool_ptr) = true;
+    a_ptr_and_b.1.1
+}
+
+// If going through a deref (and there are no other mutating accesses), then `readonly` is fine.
+// CHECK: i1 @third(ptr noalias{{( nocapture)?}} noundef readonly align {{[0-9]+}}{{( captures\(none\))?}} dereferenceable({{[0-9]+}}) %a_ptr_and_b)
+#[no_mangle]
+pub unsafe fn third(a_ptr_and_b: (*mut (i32, bool), (i64, bool))) -> bool {
+    let b_bool_ptr = core::ptr::addr_of!((*a_ptr_and_b.0).1).cast_mut();
+    (*b_bool_ptr) = true;
+    a_ptr_and_b.1.1
+}
diff --git a/tests/codegen-llvm/adjustments.rs b/tests/codegen-llvm/adjustments.rs
new file mode 100644
index 00000000000..7f7831def08
--- /dev/null
+++ b/tests/codegen-llvm/adjustments.rs
@@ -0,0 +1,28 @@
+//@ compile-flags: -C no-prepopulate-passes -Copt-level=0
+
+#![crate_type = "lib"]
+
+// Hack to get the correct size for the length part in slices
+// CHECK: @helper([[USIZE:i[0-9]+]] %_1)
+#[no_mangle]
+pub fn helper(_: usize) {}
+
+// CHECK-LABEL: @no_op_slice_adjustment
+#[no_mangle]
+pub fn no_op_slice_adjustment(x: &[u8]) -> &[u8] {
+    // We used to generate an extra alloca and memcpy for the block's trailing expression value, so
+    // check that we copy directly to the return value slot
+    // CHECK: %0 = insertvalue { ptr, [[USIZE]] } poison, ptr %x.0, 0
+    // CHECK: %1 = insertvalue { ptr, [[USIZE]] } %0, [[USIZE]] %x.1, 1
+    // CHECK: ret { ptr, [[USIZE]] } %1
+    { x }
+}
+
+// CHECK-LABEL: @no_op_slice_adjustment2
+#[no_mangle]
+pub fn no_op_slice_adjustment2(x: &[u8]) -> &[u8] {
+    // We used to generate an extra alloca and memcpy for the function's return value, so check
+    // that there's no memcpy (the slice is written to sret_slot element-wise)
+    // CHECK-NOT: call void @llvm.memcpy.
+    no_op_slice_adjustment(x)
+}
diff --git a/tests/codegen-llvm/align-byval-alignment-mismatch.rs b/tests/codegen-llvm/align-byval-alignment-mismatch.rs
new file mode 100644
index 00000000000..c69fc2de9d2
--- /dev/null
+++ b/tests/codegen-llvm/align-byval-alignment-mismatch.rs
@@ -0,0 +1,126 @@
+// ignore-tidy-linelength
+//@ add-core-stubs
+//@ revisions:i686-linux x86_64-linux
+
+//@ compile-flags: -Cno-prepopulate-passes -Copt-level=1 -Cpanic=abort
+//@[i686-linux] compile-flags: --target i686-unknown-linux-gnu
+//@[i686-linux] needs-llvm-components: x86
+//@[x86_64-linux] compile-flags: --target x86_64-unknown-linux-gnu
+//@[x86_64-linux] needs-llvm-components: x86
+
+// Tests that we correctly copy arguments into allocas when the alignment of the byval argument
+// is different from the alignment of the Rust type.
+
+// For the following test cases:
+// All of the `*_decreases_alignment` functions should codegen to a direct call, since the
+// alignment is already sufficient.
+// All off the `*_increases_alignment` functions should copy the argument to an alloca
+// on i686-unknown-linux-gnu, since the alignment needs to be increased, and should codegen
+// to a direct call on x86_64-unknown-linux-gnu, where byval alignment matches Rust alignment.
+
+#![feature(no_core)]
+#![crate_type = "lib"]
+#![no_std]
+#![no_core]
+#![allow(non_camel_case_types)]
+
+extern crate minicore;
+use minicore::*;
+
+// This type has align 1 in Rust, but as a byval argument on i686-linux, it will have align 4.
+#[repr(C)]
+#[repr(packed)]
+struct Align1 {
+    x: u128,
+    y: u128,
+    z: u128,
+}
+
+// This type has align 16 in Rust, but as a byval argument on i686-linux, it will have align 4.
+#[repr(C)]
+#[repr(align(16))]
+struct Align16 {
+    x: u128,
+    y: u128,
+    z: u128,
+}
+
+extern "C" {
+    fn extern_c_align1(x: Align1);
+    fn extern_c_align16(x: Align16);
+}
+
+// CHECK-LABEL: @rust_to_c_increases_alignment
+#[no_mangle]
+pub unsafe fn rust_to_c_increases_alignment(x: Align1) {
+    // i686-linux: start:
+    // i686-linux-NEXT: [[ALLOCA:%[0-9a-z]+]] = alloca [48 x i8], align 4
+    // i686-linux-NEXT: call void @llvm.lifetime.start.p0(i64 48, ptr {{.*}}[[ALLOCA]])
+    // i686-linux-NEXT: call void @llvm.memcpy.{{.+}}(ptr {{.*}}align 4 {{.*}}[[ALLOCA]], ptr {{.*}}align 1 {{.*}}%x
+    // i686-linux-NEXT: call void @extern_c_align1({{.+}} [[ALLOCA]])
+    // i686-linux-NEXT: call void @llvm.lifetime.end.p0(i64 48, ptr {{.*}}[[ALLOCA]])
+
+    // x86_64-linux: start:
+    // x86_64-linux-NEXT: call void @extern_c_align1
+    extern_c_align1(x);
+}
+
+// CHECK-LABEL: @rust_to_c_decreases_alignment
+#[no_mangle]
+pub unsafe fn rust_to_c_decreases_alignment(x: Align16) {
+    // CHECK: start:
+    // CHECK-NEXT: call void @extern_c_align16
+    extern_c_align16(x);
+}
+
+extern "Rust" {
+    fn extern_rust_align1(x: Align1);
+    fn extern_rust_align16(x: Align16);
+}
+
+// CHECK-LABEL: @c_to_rust_decreases_alignment
+#[no_mangle]
+pub unsafe extern "C" fn c_to_rust_decreases_alignment(x: Align1) {
+    // CHECK: start:
+    // CHECK-NEXT: call void @extern_rust_align1
+    extern_rust_align1(x);
+}
+
+// CHECK-LABEL: @c_to_rust_increases_alignment
+#[no_mangle]
+pub unsafe extern "C" fn c_to_rust_increases_alignment(x: Align16) {
+    // i686-linux: start:
+    // i686-linux-NEXT: [[ALLOCA:%[0-9a-z]+]] = alloca [48 x i8], align 16
+    // i686-linux-NEXT: call void @llvm.memcpy.{{.+}}(ptr {{.*}}align 16 {{.*}}[[ALLOCA]], ptr {{.*}}align 4 {{.*}}%0
+    // i686-linux-NEXT: call void @extern_rust_align16({{.+}} [[ALLOCA]])
+
+    // x86_64-linux: start:
+    // x86_64-linux-NEXT: call void @extern_rust_align16
+    extern_rust_align16(x);
+}
+
+extern "Rust" {
+    fn extern_rust_ref_align1(x: &Align1);
+    fn extern_rust_ref_align16(x: &Align16);
+}
+
+// CHECK-LABEL: @c_to_rust_ref_decreases_alignment
+#[no_mangle]
+pub unsafe extern "C" fn c_to_rust_ref_decreases_alignment(x: Align1) {
+    // CHECK: start:
+    // CHECK-NEXT: call void @extern_rust_ref_align1
+    extern_rust_ref_align1(&x);
+}
+
+// CHECK-LABEL: @c_to_rust_ref_increases_alignment
+#[no_mangle]
+pub unsafe extern "C" fn c_to_rust_ref_increases_alignment(x: Align16) {
+    // i686-linux: start:
+    // i686-linux-NEXT: [[ALLOCA:%[0-9a-z]+]] = alloca [48 x i8], align 16
+    // i686-linux-NEXT: call void @llvm.memcpy.{{.+}}(ptr {{.*}}align 16 {{.*}}[[ALLOCA]], ptr {{.*}}align 4 {{.*}}%0
+    // i686-linux-NEXT: call void @extern_rust_ref_align16({{.+}} [[ALLOCA]])
+
+    // x86_64-linux: start:
+    // x86_64-linux-NEXT: call void @extern_rust_ref_align16
+    extern_rust_ref_align16(&x);
+}
diff --git a/tests/codegen-llvm/align-byval-vector.rs b/tests/codegen-llvm/align-byval-vector.rs
new file mode 100644
index 00000000000..c33b41a7bbe
--- /dev/null
+++ b/tests/codegen-llvm/align-byval-vector.rs
@@ -0,0 +1,55 @@
+//@ add-core-stubs
+//@ revisions:x86-linux x86-darwin
+
+//@[x86-linux] compile-flags: --target i686-unknown-linux-gnu
+//@[x86-linux] needs-llvm-components: x86
+//@[x86-darwin] compile-flags: --target i686-apple-darwin
+//@[x86-darwin] needs-llvm-components: x86
+
+// Tests that aggregates containing vector types get their alignment increased to 16 on Darwin.
+
+#![feature(no_core, repr_simd, simd_ffi)]
+#![crate_type = "lib"]
+#![no_std]
+#![no_core]
+#![allow(non_camel_case_types)]
+
+extern crate minicore;
+use minicore::*;
+
+#[repr(simd)]
+pub struct i32x4([i32; 4]);
+
+#[repr(C)]
+pub struct Foo {
+    a: i32x4,
+    b: i8,
+}
+
+// This tests that we recursively check for vector types, not just at the top level.
+#[repr(C)]
+pub struct DoubleFoo {
+    one: Foo,
+    two: Foo,
+}
+
+extern "C" {
+    // x86-linux: declare void @f({{.*}}byval([32 x i8]) align 4{{.*}})
+    // x86-darwin: declare void @f({{.*}}byval([32 x i8]) align 16{{.*}})
+    fn f(foo: Foo);
+
+    // x86-linux: declare void @g({{.*}}byval([64 x i8]) align 4{{.*}})
+    // x86-darwin: declare void @g({{.*}}byval([64 x i8]) align 16{{.*}})
+    fn g(foo: DoubleFoo);
+}
+
+pub fn main() {
+    unsafe { f(Foo { a: i32x4([1, 2, 3, 4]), b: 0 }) }
+
+    unsafe {
+        g(DoubleFoo {
+            one: Foo { a: i32x4([1, 2, 3, 4]), b: 0 },
+            two: Foo { a: i32x4([1, 2, 3, 4]), b: 0 },
+        })
+    }
+}
diff --git a/tests/codegen-llvm/align-byval.rs b/tests/codegen-llvm/align-byval.rs
new file mode 100644
index 00000000000..75dabd74a79
--- /dev/null
+++ b/tests/codegen-llvm/align-byval.rs
@@ -0,0 +1,315 @@
+// ignore-tidy-linelength
+//@ add-core-stubs
+//@ revisions:m68k x86_64-linux x86_64-windows i686-linux i686-windows
+
+//@[m68k] compile-flags: --target m68k-unknown-linux-gnu
+//@[m68k] needs-llvm-components: m68k
+//@[x86_64-linux] compile-flags: --target x86_64-unknown-linux-gnu
+//@[x86_64-linux] needs-llvm-components: x86
+//@[x86_64-windows] compile-flags: --target x86_64-pc-windows-msvc
+//@[x86_64-windows] needs-llvm-components: x86
+//@[i686-linux] compile-flags: --target i686-unknown-linux-gnu
+//@[i686-linux] needs-llvm-components: x86
+//@[i686-windows] compile-flags: --target i686-pc-windows-msvc
+//@[i686-windows] needs-llvm-components: x86
+
+// Tests that `byval` alignment is properly specified (#80127).
+// The only targets that use `byval` are m68k, x86-64, and x86.
+// Note also that Windows mandates a by-ref ABI here, so it does not use byval.
+
+#![feature(no_core)]
+#![crate_type = "lib"]
+#![no_std]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+// This struct can be represented as a pair, so it exercises the OperandValue::Pair
+// codepath in `codegen_argument`.
+#[repr(C)]
+pub struct NaturalAlign1 {
+    a: i8,
+    b: i8,
+}
+
+// This struct cannot be represented as an immediate, so it exercises the OperandValue::Ref
+// codepath in `codegen_argument`.
+#[repr(C)]
+pub struct NaturalAlign2 {
+    a: [i16; 16],
+    b: i16,
+}
+
+#[repr(C)]
+#[repr(align(4))]
+pub struct ForceAlign4 {
+    a: [i8; 16],
+    b: i8,
+}
+
+// On i686-windows, this is passed on stack using `byval`
+#[repr(C)]
+pub struct NaturalAlign8 {
+    a: i64,
+    b: i64,
+    c: i64,
+}
+
+// On i686-windows, this is passed by reference (because alignment is >4 and requested/forced),
+// even though it has the exact same layout as `NaturalAlign8`!
+#[repr(C)]
+#[repr(align(8))]
+pub struct ForceAlign8 {
+    a: i64,
+    b: i64,
+    c: i64,
+}
+
+// On i686-windows, this is passed on stack, because requested alignment is <=4.
+#[repr(C)]
+#[repr(align(4))]
+pub struct LowerFA8 {
+    a: i64,
+    b: i64,
+    c: i64,
+}
+
+// On i686-windows, this is passed by reference, because it contains a field with
+// requested/forced alignment.
+#[repr(C)]
+pub struct WrappedFA8 {
+    a: ForceAlign8,
+}
+
+// On i686-windows, this has the same ABI as ForceAlign8, i.e. passed by reference.
+#[repr(transparent)]
+pub struct TransparentFA8 {
+    _0: (),
+    a: ForceAlign8,
+}
+
+#[repr(C)]
+#[repr(align(16))]
+pub struct ForceAlign16 {
+    a: [i32; 16],
+    b: i8,
+}
+
+// CHECK-LABEL: @call_na1
+#[no_mangle]
+pub unsafe fn call_na1(x: NaturalAlign1) {
+    // CHECK: start:
+
+    // m68k: [[ALLOCA:%[a-z0-9+]]] = alloca [2 x i8], align 1
+    // m68k: call void @natural_align_1({{.*}}byval([2 x i8]) align 1{{.*}} [[ALLOCA]])
+
+    // x86_64-linux: call void @natural_align_1(i16
+
+    // x86_64-windows: call void @natural_align_1(i16
+
+    // i686-linux: [[ALLOCA:%[a-z0-9+]]] = alloca [2 x i8], align 4
+    // i686-linux: call void @natural_align_1({{.*}}byval([2 x i8]) align 4{{.*}} [[ALLOCA]])
+
+    // i686-windows: [[ALLOCA:%[a-z0-9+]]] = alloca [2 x i8], align 4
+    // i686-windows: call void @natural_align_1({{.*}}byval([2 x i8]) align 4{{.*}} [[ALLOCA]])
+    natural_align_1(x);
+}
+
+// CHECK-LABEL: @call_na2
+#[no_mangle]
+pub unsafe fn call_na2(x: NaturalAlign2) {
+    // CHECK: start:
+
+    // m68k-NEXT: call void @natural_align_2
+    // x86_64-linux-NEXT: call void @natural_align_2
+    // x86_64-windows-NEXT: call void @natural_align_2
+
+    // i686-linux: [[ALLOCA:%[0-9]+]] = alloca [34 x i8], align 4
+    // i686-linux: call void @natural_align_2({{.*}}byval([34 x i8]) align 4{{.*}} [[ALLOCA]])
+
+    // i686-windows: [[ALLOCA:%[0-9]+]] = alloca [34 x i8], align 4
+    // i686-windows: call void @natural_align_2({{.*}}byval([34 x i8]) align 4{{.*}} [[ALLOCA]])
+    natural_align_2(x);
+}
+
+// CHECK-LABEL: @call_fa4
+#[no_mangle]
+pub unsafe fn call_fa4(x: ForceAlign4) {
+    // CHECK: start:
+    // CHECK-NEXT: call void @force_align_4
+    force_align_4(x);
+}
+
+// CHECK-LABEL: @call_na8
+#[no_mangle]
+pub unsafe fn call_na8(x: NaturalAlign8) {
+    // CHECK: start:
+    // CHECK-NEXT: call void @natural_align_8
+    natural_align_8(x);
+}
+
+// CHECK-LABEL: @call_fa8
+#[no_mangle]
+pub unsafe fn call_fa8(x: ForceAlign8) {
+    // CHECK: start:
+    // CHECK-NEXT: call void @force_align_8
+    force_align_8(x);
+}
+
+// CHECK-LABEL: @call_lfa8
+#[no_mangle]
+pub unsafe fn call_lfa8(x: LowerFA8) {
+    // CHECK: start:
+    // CHECK-NEXT: call void @lower_fa8
+    lower_fa8(x);
+}
+
+// CHECK-LABEL: @call_wfa8
+#[no_mangle]
+pub unsafe fn call_wfa8(x: WrappedFA8) {
+    // CHECK: start:
+    // CHECK-NEXT: call void @wrapped_fa8
+    wrapped_fa8(x);
+}
+
+// CHECK-LABEL: @call_tfa8
+#[no_mangle]
+pub unsafe fn call_tfa8(x: TransparentFA8) {
+    // CHECK: start:
+    // CHECK-NEXT: call void @transparent_fa8
+    transparent_fa8(x);
+}
+
+// CHECK-LABEL: @call_fa16
+#[no_mangle]
+pub unsafe fn call_fa16(x: ForceAlign16) {
+    // CHECK: start:
+    // CHECK-NEXT: call void @force_align_16
+    force_align_16(x);
+}
+
+extern "C" {
+    // m68k: declare void @natural_align_1({{.*}}byval([2 x i8]) align 1{{.*}})
+
+    // x86_64-linux: declare void @natural_align_1(i16)
+
+    // x86_64-windows: declare void @natural_align_1(i16)
+
+    // i686-linux: declare void @natural_align_1({{.*}}byval([2 x i8]) align 4{{.*}})
+
+    // i686-windows: declare void @natural_align_1({{.*}}byval([2 x i8]) align 4{{.*}})
+    fn natural_align_1(x: NaturalAlign1);
+
+    // m68k: declare void @natural_align_2({{.*}}byval([34 x i8]) align 2{{.*}})
+
+    // x86_64-linux: declare void @natural_align_2({{.*}}byval([34 x i8]) align 2{{.*}})
+
+    // x86_64-windows: declare void @natural_align_2(
+    // x86_64-windows-NOT: byval
+    // x86_64-windows-SAME: align 2{{.*}})
+
+    // i686-linux: declare void @natural_align_2({{.*}}byval([34 x i8]) align 4{{.*}})
+
+    // i686-windows: declare void @natural_align_2({{.*}}byval([34 x i8]) align 4{{.*}})
+    fn natural_align_2(x: NaturalAlign2);
+
+    // m68k: declare void @force_align_4({{.*}}byval([20 x i8]) align 4{{.*}})
+
+    // x86_64-linux: declare void @force_align_4({{.*}}byval([20 x i8]) align 4{{.*}})
+
+    // x86_64-windows: declare void @force_align_4(
+    // x86_64-windows-NOT: byval
+    // x86_64-windows-SAME: align 4{{.*}})
+
+    // i686-linux: declare void @force_align_4({{.*}}byval([20 x i8]) align 4{{.*}})
+
+    // i686-windows: declare void @force_align_4({{.*}}byval([20 x i8]) align 4{{.*}})
+    fn force_align_4(x: ForceAlign4);
+
+    // m68k: declare void @natural_align_8({{.*}}byval([24 x i8]) align 4{{.*}})
+
+    // x86_64-linux: declare void @natural_align_8({{.*}}byval([24 x i8]) align 8{{.*}})
+
+    // x86_64-windows: declare void @natural_align_8(
+    // x86_64-windows-NOT: byval
+    // x86_64-windows-SAME: align 8{{.*}})
+
+    // i686-linux: declare void @natural_align_8({{.*}}byval([24 x i8]) align 4{{.*}})
+
+    // i686-windows: declare void @natural_align_8({{.*}}byval([24 x i8]) align 4{{.*}})
+    fn natural_align_8(x: NaturalAlign8);
+
+    // m68k: declare void @force_align_8({{.*}}byval([24 x i8]) align 8{{.*}})
+
+    // x86_64-linux: declare void @force_align_8({{.*}}byval([24 x i8]) align 8{{.*}})
+
+    // x86_64-windows: declare void @force_align_8(
+    // x86_64-windows-NOT: byval
+    // x86_64-windows-SAME: align 8{{.*}})
+
+    // i686-linux: declare void @force_align_8({{.*}}byval([24 x i8]) align 4{{.*}})
+
+    // i686-windows: declare void @force_align_8(
+    // i686-windows-NOT: byval
+    // i686-windows-SAME: align 8{{.*}})
+    fn force_align_8(x: ForceAlign8);
+
+    // m68k: declare void @lower_fa8({{.*}}byval([24 x i8]) align 4{{.*}})
+
+    // x86_64-linux: declare void @lower_fa8({{.*}}byval([24 x i8]) align 8{{.*}})
+
+    // x86_64-windows: declare void @lower_fa8(
+    // x86_64-windows-NOT: byval
+    // x86_64-windows-SAME: align 8{{.*}})
+
+    // i686-linux: declare void @lower_fa8({{.*}}byval([24 x i8]) align 4{{.*}})
+
+    // i686-windows: declare void @lower_fa8({{.*}}byval([24 x i8]) align 4{{.*}})
+    fn lower_fa8(x: LowerFA8);
+
+    // m68k: declare void @wrapped_fa8({{.*}}byval([24 x i8]) align 8{{.*}})
+
+    // x86_64-linux: declare void @wrapped_fa8({{.*}}byval([24 x i8]) align 8{{.*}})
+
+    // x86_64-windows: declare void @wrapped_fa8(
+    // x86_64-windows-NOT: byval
+    // x86_64-windows-SAME: align 8{{.*}})
+
+    // i686-linux: declare void @wrapped_fa8({{.*}}byval([24 x i8]) align 4{{.*}})
+
+    // i686-windows: declare void @wrapped_fa8(
+    // i686-windows-NOT: byval
+    // i686-windows-SAME: align 8{{.*}})
+    fn wrapped_fa8(x: WrappedFA8);
+
+    // m68k: declare void @transparent_fa8({{.*}}byval([24 x i8]) align 8{{.*}})
+
+    // x86_64-linux: declare void @transparent_fa8({{.*}}byval([24 x i8]) align 8{{.*}})
+
+    // x86_64-windows: declare void @transparent_fa8(
+    // x86_64-windows-NOT: byval
+    // x86_64-windows-SAME: align 8{{.*}})
+
+    // i686-linux: declare void @transparent_fa8({{.*}}byval([24 x i8]) align 4{{.*}})
+
+    // i686-windows: declare void @transparent_fa8(
+    // i686-windows-NOT: byval
+    // i686-windows-SAME: align 8{{.*}})
+    fn transparent_fa8(x: TransparentFA8);
+
+    // m68k: declare void @force_align_16({{.*}}byval([80 x i8]) align 16{{.*}})
+
+    // x86_64-linux: declare void @force_align_16({{.*}}byval([80 x i8]) align 16{{.*}})
+
+    // x86_64-windows: declare void @force_align_16(
+    // x86_64-windows-NOT: byval
+    // x86_64-windows-SAME: align 16{{.*}})
+
+    // i686-linux: declare void @force_align_16({{.*}}byval([80 x i8]) align 4{{.*}})
+
+    // i686-windows: declare void @force_align_16(
+    // i686-windows-NOT: byval
+    // i686-windows-SAME: align 16{{.*}})
+    fn force_align_16(x: ForceAlign16);
+}
diff --git a/tests/codegen-llvm/align-enum.rs b/tests/codegen-llvm/align-enum.rs
new file mode 100644
index 00000000000..e8dd95d3afb
--- /dev/null
+++ b/tests/codegen-llvm/align-enum.rs
@@ -0,0 +1,33 @@
+//@ compile-flags: -C no-prepopulate-passes -Z mir-opt-level=0
+//
+
+#![crate_type = "lib"]
+
+#[repr(align(64))]
+pub enum Align64 {
+    A(u32),
+    B(u32),
+}
+
+pub struct Nested64 {
+    a: u8,
+    b: Align64,
+    c: u16,
+}
+
+// CHECK-LABEL: @align64
+#[no_mangle]
+pub fn align64(a: u32) -> Align64 {
+    // CHECK: %a64 = alloca [64 x i8], align 64
+    // CHECK: call void @llvm.memcpy.{{.*}}(ptr align 64 %{{.*}}, ptr align 64 %{{.*}}, i{{[0-9]+}} 64, i1 false)
+    let a64 = Align64::A(a);
+    a64
+}
+
+// CHECK-LABEL: @nested64
+#[no_mangle]
+pub fn nested64(a: u8, b: u32, c: u16) -> Nested64 {
+    // CHECK: %n64 = alloca [128 x i8], align 64
+    let n64 = Nested64 { a, b: Align64::B(b), c };
+    n64
+}
diff --git a/tests/codegen-llvm/align-fn.rs b/tests/codegen-llvm/align-fn.rs
new file mode 100644
index 00000000000..cbc24e2ae2e
--- /dev/null
+++ b/tests/codegen-llvm/align-fn.rs
@@ -0,0 +1,143 @@
+//@ compile-flags: -C no-prepopulate-passes -Z mir-opt-level=0 -Clink-dead-code
+//@ edition: 2024
+//@ ignore-wasm32 aligning functions is not currently supported on wasm (#143368)
+
+#![crate_type = "lib"]
+// FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity
+#![feature(rustc_attrs)]
+#![feature(fn_align)]
+
+// CHECK: align 16
+#[unsafe(no_mangle)]
+#[rustc_align(16)]
+pub fn fn_align() {}
+
+pub struct A;
+
+impl A {
+    // CHECK: align 16
+    #[unsafe(no_mangle)]
+    #[rustc_align(16)]
+    pub fn method_align(self) {}
+
+    // CHECK: align 16
+    #[unsafe(no_mangle)]
+    #[rustc_align(16)]
+    pub fn associated_fn() {}
+}
+
+trait T: Sized {
+    fn trait_fn() {}
+
+    fn trait_method(self) {}
+
+    #[rustc_align(8)]
+    fn trait_method_inherit_low(self);
+
+    #[rustc_align(32)]
+    fn trait_method_inherit_high(self);
+
+    #[rustc_align(32)]
+    fn trait_method_inherit_default(self) {}
+
+    #[rustc_align(4)]
+    #[rustc_align(128)]
+    #[rustc_align(8)]
+    fn inherit_highest(self) {}
+}
+
+impl T for A {
+    // CHECK-LABEL: trait_fn
+    // CHECK-SAME: align 16
+    #[unsafe(no_mangle)]
+    #[rustc_align(16)]
+    fn trait_fn() {}
+
+    // CHECK-LABEL: trait_method
+    // CHECK-SAME: align 16
+    #[unsafe(no_mangle)]
+    #[rustc_align(16)]
+    fn trait_method(self) {}
+
+    // The prototype's align is ignored because the align here is higher.
+    // CHECK-LABEL: trait_method_inherit_low
+    // CHECK-SAME: align 16
+    #[unsafe(no_mangle)]
+    #[rustc_align(16)]
+    fn trait_method_inherit_low(self) {}
+
+    // The prototype's align is used because it is higher.
+    // CHECK-LABEL: trait_method_inherit_high
+    // CHECK-SAME: align 32
+    #[unsafe(no_mangle)]
+    #[rustc_align(16)]
+    fn trait_method_inherit_high(self) {}
+
+    // The prototype's align inherited.
+    // CHECK-LABEL: trait_method_inherit_default
+    // CHECK-SAME: align 32
+    #[unsafe(no_mangle)]
+    fn trait_method_inherit_default(self) {}
+
+    // The prototype's highest align inherited.
+    // CHECK-LABEL: inherit_highest
+    // CHECK-SAME: align 128
+    #[unsafe(no_mangle)]
+    #[rustc_align(32)]
+    #[rustc_align(64)]
+    fn inherit_highest(self) {}
+}
+
+trait HasDefaultImpl: Sized {
+    // CHECK-LABEL: inherit_from_default_method
+    // CHECK-LABEL: inherit_from_default_method
+    // CHECK-SAME: align 32
+    #[rustc_align(32)]
+    fn inherit_from_default_method(self) {}
+}
+
+pub struct InstantiateDefaultMethods;
+
+impl HasDefaultImpl for InstantiateDefaultMethods {}
+
+// CHECK-LABEL: align_specified_twice_1
+// CHECK-SAME: align 64
+#[unsafe(no_mangle)]
+#[rustc_align(32)]
+#[rustc_align(64)]
+pub fn align_specified_twice_1() {}
+
+// CHECK-LABEL: align_specified_twice_2
+// CHECK-SAME: align 128
+#[unsafe(no_mangle)]
+#[rustc_align(128)]
+#[rustc_align(32)]
+pub fn align_specified_twice_2() {}
+
+// CHECK-LABEL: align_specified_twice_3
+// CHECK-SAME: align 256
+#[unsafe(no_mangle)]
+#[rustc_align(32)]
+#[rustc_align(256)]
+pub fn align_specified_twice_3() {}
+
+const _: () = {
+    // CHECK-LABEL: align_unmangled
+    // CHECK-SAME: align 256
+    #[unsafe(no_mangle)]
+    #[rustc_align(32)]
+    #[rustc_align(256)]
+    extern "C" fn align_unmangled() {}
+};
+
+unsafe extern "C" {
+    #[rustc_align(256)]
+    fn align_unmangled();
+}
+
+// FIXME also check `gen` et al
+// CHECK-LABEL: async_align
+// CHECK-SAME: align 64
+#[unsafe(no_mangle)]
+#[rustc_align(64)]
+pub async fn async_align() {}
diff --git a/tests/codegen-llvm/align-offset.rs b/tests/codegen-llvm/align-offset.rs
new file mode 100644
index 00000000000..21062cc0a91
--- /dev/null
+++ b/tests/codegen-llvm/align-offset.rs
@@ -0,0 +1,75 @@
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @align8
+#[no_mangle]
+pub fn align8(p: *const u8) -> bool {
+    // CHECK: ret i1 true
+    p.align_offset(8) < 8
+}
+
+#[repr(align(4))]
+pub struct Align4([u8; 4]);
+
+// CHECK-LABEL: @align_to4
+#[no_mangle]
+pub fn align_to4(x: &[u8]) -> bool {
+    // CHECK: ret i1 true
+    let (prefix, _middle, suffix) = unsafe { x.align_to::<Align4>() };
+    prefix.len() < 4 && suffix.len() < 4
+}
+
+// CHECK-LABEL: @align_offset_byte_ptr(ptr{{.+}}%ptr)
+#[no_mangle]
+pub fn align_offset_byte_ptr(ptr: *const u8) -> usize {
+    // CHECK: %[[ADDR:.+]] = ptrtoint ptr %ptr to [[USIZE:i[0-9]+]]
+    // CHECK: %[[UP:.+]] = add [[USIZE]] %[[ADDR]], 31
+    // CHECK: %[[ALIGNED:.+]] = and [[USIZE]] %[[UP]], -32
+    // CHECK: %[[OFFSET:.+]] = sub [[USIZE]] %[[ALIGNED]], %[[ADDR]]
+
+    // Since we're offsetting a byte pointer, there's no further fixups
+    // CHECK-NOT: shr
+    // CHECK-NOT: div
+    // CHECK-NOT: select
+
+    // CHECK: ret [[USIZE]] %[[OFFSET]]
+    ptr.align_offset(32)
+}
+
+// CHECK-LABEL: @align_offset_word_slice(ptr{{.+}}align 4{{.+}}%slice.0
+#[no_mangle]
+pub fn align_offset_word_slice(slice: &[Align4]) -> usize {
+    // CHECK: %[[ADDR:.+]] = ptrtoint ptr %slice.0 to [[USIZE]]
+    // CHECK: %[[UP:.+]] = add [[USIZE]] %[[ADDR]], 31
+    // CHECK: %[[ALIGNED:.+]] = and [[USIZE]] %[[UP]], -32
+    // CHECK: %[[BOFFSET:.+]] = sub [[USIZE]] %[[ALIGNED]], %[[ADDR]]
+    // CHECK: %[[OFFSET:.+]] = lshr exact [[USIZE]] %[[BOFFSET]], 2
+
+    // Slices are known to be aligned, so we don't need the "maybe -1" path
+    // CHECK-NOT: select
+
+    // CHECK: ret [[USIZE]] %[[OFFSET]]
+    slice.as_ptr().align_offset(32)
+}
+
+// CHECK-LABEL: @align_offset_word_ptr(ptr{{.+}}%ptr
+#[no_mangle]
+pub fn align_offset_word_ptr(ptr: *const Align4) -> usize {
+    // CHECK: %[[ADDR:.+]] = ptrtoint ptr %ptr to [[USIZE]]
+    // CHECK: %[[UP:.+]] = add [[USIZE]] %[[ADDR]], 31
+    // CHECK: %[[ALIGNED:.+]] = and [[USIZE]] %[[UP]], -32
+    // CHECK: %[[BOFFSET:.+]] = sub [[USIZE]] %[[ALIGNED]], %[[ADDR]]
+
+    // While we can always get a *byte* offset that will work, if the original
+    // pointer is unaligned it might be impossible to return an *element* offset
+    // that will make it aligned. We want it to be a `select`, not a `br`, so
+    // that the assembly will be branchless.
+    // CHECK: %[[LOW:.+]] = and [[USIZE]] %[[ADDR]], 3
+    // CHECK: %[[ORIGINAL_ALIGNED:.+]] = icmp eq [[USIZE]] %[[LOW]], 0
+    // CHECK: %[[OFFSET:.+]] = lshr exact [[USIZE]] %[[BOFFSET]], 2
+    // CHECK: %[[R:.+]] = select i1 %[[ORIGINAL_ALIGNED]], [[USIZE]] %[[OFFSET]], [[USIZE]] -1
+
+    // CHECK: ret [[USIZE]] %[[R]]
+    ptr.align_offset(32)
+}
diff --git a/tests/codegen-llvm/align-struct.rs b/tests/codegen-llvm/align-struct.rs
new file mode 100644
index 00000000000..d4cc65e9158
--- /dev/null
+++ b/tests/codegen-llvm/align-struct.rs
@@ -0,0 +1,70 @@
+//@ compile-flags: -C no-prepopulate-passes -Z mir-opt-level=0
+// 32bit MSVC does not align things properly so we suppress high alignment annotations (#112480)
+//@ ignore-i686-pc-windows-msvc
+//@ ignore-i686-pc-windows-gnu
+
+#![crate_type = "lib"]
+
+#[repr(align(64))]
+pub struct Align64(i32);
+
+pub struct Nested64 {
+    a: Align64,
+    b: i32,
+    c: i32,
+    d: i8,
+}
+
+// This has the extra field in B to ensure it's not ScalarPair,
+// and thus that the test actually emits it via memory, not `insertvalue`.
+pub enum Enum4 {
+    A(i32),
+    B(i32, i32),
+}
+
+pub enum Enum64 {
+    A(Align64),
+    B(i32),
+}
+
+// CHECK-LABEL: @align64
+#[no_mangle]
+pub fn align64(i: i32) -> Align64 {
+    // CHECK: %a64 = alloca [64 x i8], align 64
+    // CHECK: call void @llvm.memcpy.{{.*}}(ptr align 64 %{{.*}}, ptr align 64 %{{.*}}, i{{[0-9]+}} 64, i1 false)
+    let a64 = Align64(i);
+    a64
+}
+
+// For issue 54028: make sure that we are specifying the correct alignment for fields of aligned
+// structs
+// CHECK-LABEL: @align64_load
+#[no_mangle]
+pub fn align64_load(a: Align64) -> i32 {
+    // CHECK: {{%.*}} = load i32, ptr {{%.*}}, align 64
+    a.0
+}
+
+// CHECK-LABEL: @nested64
+#[no_mangle]
+pub fn nested64(a: Align64, b: i32, c: i32, d: i8) -> Nested64 {
+    // CHECK: %n64 = alloca [128 x i8], align 64
+    let n64 = Nested64 { a, b, c, d };
+    n64
+}
+
+// CHECK-LABEL: @enum4
+#[no_mangle]
+pub fn enum4(a: i32) -> Enum4 {
+    // CHECK: %e4 = alloca [12 x i8], align 4
+    let e4 = Enum4::A(a);
+    e4
+}
+
+// CHECK-LABEL: @enum64
+#[no_mangle]
+pub fn enum64(a: Align64) -> Enum64 {
+    // CHECK: %e64 = alloca [128 x i8], align 64
+    let e64 = Enum64::A(a);
+    e64
+}
diff --git a/tests/codegen-llvm/alloc-optimisation.rs b/tests/codegen-llvm/alloc-optimisation.rs
new file mode 100644
index 00000000000..3735860d510
--- /dev/null
+++ b/tests/codegen-llvm/alloc-optimisation.rs
@@ -0,0 +1,13 @@
+//@ compile-flags: -Copt-level=3
+#![crate_type = "lib"]
+
+#[no_mangle]
+pub fn alloc_test(data: u32) {
+    // CHECK-LABEL: @alloc_test
+    // CHECK-NEXT: start:
+    // CHECK-NEXT: ; call __rustc::__rust_no_alloc_shim_is_unstable_v2
+    // CHECK-NEXT: tail call void @_R{{.+}}__rust_no_alloc_shim_is_unstable_v2()
+    // CHECK-NEXT: ret void
+    let x = Box::new(data);
+    drop(x);
+}
diff --git a/tests/codegen-llvm/amdgpu-addrspacecast.rs b/tests/codegen-llvm/amdgpu-addrspacecast.rs
new file mode 100644
index 00000000000..7fe630a7efa
--- /dev/null
+++ b/tests/codegen-llvm/amdgpu-addrspacecast.rs
@@ -0,0 +1,18 @@
+// Check that pointers are casted to addrspace(0) before they are used
+
+//@ compile-flags: --crate-type=rlib --target=amdgcn-amd-amdhsa -Ctarget-cpu=gfx900
+//@ needs-llvm-components: amdgpu
+//@ add-core-stubs
+#![feature(no_core)]
+#![no_core]
+
+extern crate minicore;
+
+// CHECK-LABEL: @ref_of_local
+// CHECK: [[alloca:%[0-9]]] = alloca
+// CHECK: %i = addrspacecast ptr addrspace(5) [[alloca]] to ptr
+#[no_mangle]
+pub fn ref_of_local(f: fn(&i32)) {
+    let i = 0;
+    f(&i);
+}
diff --git a/tests/codegen-llvm/array-clone.rs b/tests/codegen-llvm/array-clone.rs
new file mode 100644
index 00000000000..35445174684
--- /dev/null
+++ b/tests/codegen-llvm/array-clone.rs
@@ -0,0 +1,15 @@
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @array_clone
+#[no_mangle]
+pub fn array_clone(a: &[u8; 2]) -> [u8; 2] {
+    // CHECK-NOT: getelementptr
+    // CHECK-NOT: load i8
+    // CHECK-NOT: zext
+    // CHECK-NOT: shl
+    // CHECK: load i16
+    // CHECK-NEXT: ret i16
+    a.clone()
+}
diff --git a/tests/codegen-llvm/array-cmp.rs b/tests/codegen-llvm/array-cmp.rs
new file mode 100644
index 00000000000..0d337655401
--- /dev/null
+++ b/tests/codegen-llvm/array-cmp.rs
@@ -0,0 +1,74 @@
+// Ensure the asm for array comparisons is properly optimized.
+
+//@ compile-flags: -C opt-level=2
+//@ needs-deterministic-layouts (checks depend on tuple layout)
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @compare
+// CHECK: start:
+// CHECK-NEXT: ret i1 true
+#[no_mangle]
+pub fn compare() -> bool {
+    let bytes = 12.5f32.to_ne_bytes();
+    bytes
+        == if cfg!(target_endian = "big") {
+            [0x41, 0x48, 0x00, 0x00]
+        } else {
+            [0x00, 0x00, 0x48, 0x41]
+        }
+}
+
+// CHECK-LABEL: @array_of_tuple_le
+#[no_mangle]
+pub fn array_of_tuple_le(a: &[(i16, u16); 2], b: &[(i16, u16); 2]) -> bool {
+    // Ensure that, after all the optimizations have run, the happy path just checks
+    // `eq` on each corresponding pair and moves onto the next one if it is.
+    // Then there's a dedup'd comparison for the place that's different.
+    // (As opposed to, say, running a full `[su]cmp` as part of checking equality.)
+
+    // This is written quite specifically because different library code was triggering
+    // <https://github.com/llvm/llvm-project/issues/132678> along the way, so this
+    // has enough checks to make sure that's not happening. It doesn't need to be
+    // *exactly* this IR, but be careful if you ever need to update these checks.
+
+    // CHECK: start:
+    // CHECK: %[[A00:.+]] = load i16, ptr %a
+    // CHECK: %[[B00:.+]] = load i16, ptr %b
+    // CHECK-NOT: cmp
+    // CHECK: %[[EQ00:.+]] = icmp eq i16 %[[A00]], %[[B00]]
+    // CHECK-NEXT: br i1 %[[EQ00]], label %[[L01:.+]], label %[[EXIT_S:.+]]
+
+    // CHECK: [[L01]]:
+    // CHECK: %[[PA01:.+]] = getelementptr{{.+}}i8, ptr %a, {{i32|i64}} 2
+    // CHECK: %[[PB01:.+]] = getelementptr{{.+}}i8, ptr %b, {{i32|i64}} 2
+    // CHECK: %[[A01:.+]] = load i16, ptr %[[PA01]]
+    // CHECK: %[[B01:.+]] = load i16, ptr %[[PB01]]
+    // CHECK-NOT: cmp
+    // CHECK: %[[EQ01:.+]] = icmp eq i16 %[[A01]], %[[B01]]
+    // CHECK-NEXT: br i1 %[[EQ01]], label %[[L10:.+]], label %[[EXIT_U:.+]]
+
+    // CHECK: [[L10]]:
+    // CHECK: %[[PA10:.+]] = getelementptr{{.+}}i8, ptr %a, {{i32|i64}} 4
+    // CHECK: %[[PB10:.+]] = getelementptr{{.+}}i8, ptr %b, {{i32|i64}} 4
+    // CHECK: %[[A10:.+]] = load i16, ptr %[[PA10]]
+    // CHECK: %[[B10:.+]] = load i16, ptr %[[PB10]]
+    // CHECK-NOT: cmp
+    // CHECK: %[[EQ10:.+]] = icmp eq i16 %[[A10]], %[[B10]]
+    // CHECK-NEXT: br i1 %[[EQ10]], label %[[L11:.+]], label %[[EXIT_S]]
+
+    // CHECK: [[L11]]:
+    // CHECK: %[[PA11:.+]] = getelementptr{{.+}}i8, ptr %a, {{i32|i64}} 6
+    // CHECK: %[[PB11:.+]] = getelementptr{{.+}}i8, ptr %b, {{i32|i64}} 6
+    // CHECK: %[[A11:.+]] = load i16, ptr %[[PA11]]
+    // CHECK: %[[B11:.+]] = load i16, ptr %[[PB11]]
+    // CHECK-NOT: cmp
+    // CHECK: %[[EQ11:.+]] = icmp eq i16 %[[A11]], %[[B11]]
+    // CHECK-NEXT: br i1 %[[EQ11]], label %[[DONE:.+]], label %[[EXIT_U]]
+
+    // CHECK: [[DONE]]:
+    // CHECK: %[[RET:.+]] = phi i1 [ %{{.+}}, %[[EXIT_S]] ], [ %{{.+}}, %[[EXIT_U]] ], [ true, %[[L11]] ]
+    // CHECK: ret i1 %[[RET]]
+
+    a <= b
+}
diff --git a/tests/codegen-llvm/array-codegen.rs b/tests/codegen-llvm/array-codegen.rs
new file mode 100644
index 00000000000..9b0c6e8c347
--- /dev/null
+++ b/tests/codegen-llvm/array-codegen.rs
@@ -0,0 +1,62 @@
+//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @array_load
+#[no_mangle]
+pub fn array_load(a: &[u8; 4]) -> [u8; 4] {
+    // CHECK-NOT: alloca
+    // CHECK: %[[ALLOCA:.+]] = alloca [4 x i8], align 1
+    // CHECK-NOT: alloca
+    // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 1 %[[ALLOCA]], ptr align 1 %a, {{.+}} 4, i1 false)
+    // CHECK: %[[TEMP:.+]] = load i32, ptr %[[ALLOCA]], align 1
+    // CHECK: ret i32 %[[TEMP]]
+    *a
+}
+
+// CHECK-LABEL: @array_store
+#[no_mangle]
+pub fn array_store(a: [u8; 4], p: &mut [u8; 4]) {
+    // CHECK-NOT: alloca
+    // CHECK: %[[TEMP:.+]] = alloca [4 x i8], [[TEMPALIGN:align [0-9]+]]
+    // CHECK-NOT: alloca
+    // CHECK: %a = alloca [4 x i8]
+    // CHECK-NOT: alloca
+    // store i32 %0, ptr %[[TEMP]]
+    // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 1 %a, ptr [[TEMPALIGN]] %[[TEMP]], {{.+}} 4, i1 false)
+    // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 1 %p, ptr align 1 %a, {{.+}} 4, i1 false)
+    *p = a;
+}
+
+// CHECK-LABEL: @array_copy
+#[no_mangle]
+pub fn array_copy(a: &[u8; 4], p: &mut [u8; 4]) {
+    // CHECK-NOT: alloca
+    // CHECK: %[[LOCAL:.+]] = alloca [4 x i8], align 1
+    // CHECK-NOT: alloca
+    // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 1 %[[LOCAL]], ptr align 1 %a, {{.+}} 4, i1 false)
+    // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 1 %p, ptr align 1 %[[LOCAL]], {{.+}} 4, i1 false)
+    *p = *a;
+}
+
+// CHECK-LABEL: @array_copy_1_element
+#[no_mangle]
+pub fn array_copy_1_element(a: &[u8; 1], p: &mut [u8; 1]) {
+    // CHECK-NOT: alloca
+    // CHECK: %[[LOCAL:.+]] = alloca [1 x i8], align 1
+    // CHECK-NOT: alloca
+    // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 1 %[[LOCAL]], ptr align 1 %a, {{.+}} 1, i1 false)
+    // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 1 %p, ptr align 1 %[[LOCAL]], {{.+}} 1, i1 false)
+    *p = *a;
+}
+
+// CHECK-LABEL: @array_copy_2_elements
+#[no_mangle]
+pub fn array_copy_2_elements(a: &[u8; 2], p: &mut [u8; 2]) {
+    // CHECK-NOT: alloca
+    // CHECK: %[[LOCAL:.+]] = alloca [2 x i8], align 1
+    // CHECK-NOT: alloca
+    // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 1 %[[LOCAL]], ptr align 1 %a, {{.+}} 2, i1 false)
+    // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 1 %p, ptr align 1 %[[LOCAL]], {{.+}} 2, i1 false)
+    *p = *a;
+}
diff --git a/tests/codegen-llvm/array-equality.rs b/tests/codegen-llvm/array-equality.rs
new file mode 100644
index 00000000000..fa0475bf480
--- /dev/null
+++ b/tests/codegen-llvm/array-equality.rs
@@ -0,0 +1,101 @@
+//@ compile-flags: -Copt-level=3 -Z merge-functions=disabled
+//@ only-x86_64
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @array_eq_value
+#[no_mangle]
+pub fn array_eq_value(a: [u16; 3], b: [u16; 3]) -> bool {
+    // CHECK-NEXT: start:
+    // CHECK-NEXT: %2 = icmp eq i48 %0, %1
+    // CHECK-NEXT: ret i1 %2
+    a == b
+}
+
+// CHECK-LABEL: @array_eq_ref
+#[no_mangle]
+pub fn array_eq_ref(a: &[u16; 3], b: &[u16; 3]) -> bool {
+    // CHECK: start:
+    // CHECK: load i48, ptr %{{.+}}, align 2
+    // CHECK: load i48, ptr %{{.+}}, align 2
+    // CHECK: icmp eq i48
+    // CHECK-NEXT: ret
+    a == b
+}
+
+// CHECK-LABEL: @array_eq_value_still_passed_by_pointer
+#[no_mangle]
+pub fn array_eq_value_still_passed_by_pointer(a: [u16; 9], b: [u16; 9]) -> bool {
+    // CHECK-NEXT: start:
+    // CHECK: %[[CMP:.+]] = tail call i32 @{{bcmp|memcmp}}(ptr {{.*}} dereferenceable(18) %{{.+}}, ptr {{.*}} dereferenceable(18) %{{.+}}, i64 18)
+    // CHECK-NEXT: %[[EQ:.+]] = icmp eq i32 %[[CMP]], 0
+    // CHECK-NEXT: ret i1 %[[EQ]]
+    a == b
+}
+
+// CHECK-LABEL: @array_eq_long
+#[no_mangle]
+pub fn array_eq_long(a: &[u16; 1234], b: &[u16; 1234]) -> bool {
+    // CHECK-NEXT: start:
+    // CHECK: %[[CMP:.+]] = tail call i32 @{{bcmp|memcmp}}(ptr {{.*}} dereferenceable(2468) %{{.+}}, ptr {{.*}} dereferenceable(2468) %{{.+}}, i64 2468)
+    // CHECK-NEXT: %[[EQ:.+]] = icmp eq i32 %[[CMP]], 0
+    // CHECK-NEXT: ret i1 %[[EQ]]
+    a == b
+}
+
+// CHECK-LABEL: @array_char_eq
+#[no_mangle]
+pub fn array_char_eq(a: [char; 2], b: [char; 2]) -> bool {
+    // CHECK-NEXT: start:
+    // CHECK-NEXT: %[[EQ:.+]] = icmp eq i64 %0, %1
+    // CHECK-NEXT: ret i1 %[[EQ]]
+    a == b
+}
+
+// CHECK-LABEL: @array_eq_zero_short(i48
+#[no_mangle]
+pub fn array_eq_zero_short(x: [u16; 3]) -> bool {
+    // CHECK-NEXT: start:
+    // CHECK-NEXT: %[[EQ:.+]] = icmp eq i48 %0, 0
+    // CHECK-NEXT: ret i1 %[[EQ]]
+    x == [0; 3]
+}
+
+// CHECK-LABEL: @array_eq_none_short(i40
+#[no_mangle]
+pub fn array_eq_none_short(x: [Option<std::num::NonZero<u8>>; 5]) -> bool {
+    // CHECK-NEXT: start:
+    // CHECK-NEXT: %[[EQ:.+]] = icmp eq i40 %0, 0
+    // CHECK-NEXT: ret i1 %[[EQ]]
+    x == [None; 5]
+}
+
+// CHECK-LABEL: @array_eq_zero_nested(
+#[no_mangle]
+pub fn array_eq_zero_nested(x: [[u8; 3]; 3]) -> bool {
+    // CHECK: %[[VAL:.+]] = load i72
+    // CHECK-SAME: align 1
+    // CHECK: %[[EQ:.+]] = icmp eq i72 %[[VAL]], 0
+    // CHECK: ret i1 %[[EQ]]
+    x == [[0; 3]; 3]
+}
+
+// CHECK-LABEL: @array_eq_zero_mid(
+#[no_mangle]
+pub fn array_eq_zero_mid(x: [u16; 8]) -> bool {
+    // CHECK-NEXT: start:
+    // CHECK: %[[LOAD:.+]] = load i128,
+    // CHECK-NEXT: %[[EQ:.+]] = icmp eq i128 %[[LOAD]], 0
+    // CHECK-NEXT: ret i1 %[[EQ]]
+    x == [0; 8]
+}
+
+// CHECK-LABEL: @array_eq_zero_long(
+#[no_mangle]
+pub fn array_eq_zero_long(x: [u16; 1234]) -> bool {
+    // CHECK-NEXT: start:
+    // CHECK-NOT: alloca
+    // CHECK: %[[CMP:.+]] = tail call i32 @{{bcmp|memcmp}}(
+    // CHECK-NEXT: %[[EQ:.+]] = icmp eq i32 %[[CMP]], 0
+    // CHECK-NEXT: ret i1 %[[EQ]]
+    x == [0; 1234]
+}
diff --git a/tests/codegen-llvm/array-from_fn.rs b/tests/codegen-llvm/array-from_fn.rs
new file mode 100644
index 00000000000..7202d0c67e6
--- /dev/null
+++ b/tests/codegen-llvm/array-from_fn.rs
@@ -0,0 +1,13 @@
+//@ revisions: NORMAL OPT
+//@ [NORMAL] compile-flags: -C opt-level=0 -C debuginfo=2
+//@ [OPT] compile-flags: -C opt-level=s -C debuginfo=0
+
+#![crate_type = "lib"]
+#![feature(array_from_fn)]
+
+#[no_mangle]
+pub fn iota() -> [u8; 16] {
+    // OPT-NOT: core..array..Guard
+    // NORMAL: core..array..Guard
+    std::array::from_fn(|i| i as _)
+}
diff --git a/tests/codegen-llvm/array-map.rs b/tests/codegen-llvm/array-map.rs
new file mode 100644
index 00000000000..f49dddcfc20
--- /dev/null
+++ b/tests/codegen-llvm/array-map.rs
@@ -0,0 +1,35 @@
+//@ compile-flags: -C opt-level=3 -C target-cpu=x86-64-v3
+//@ only-x86_64
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @short_integer_map
+#[no_mangle]
+pub fn short_integer_map(x: [u32; 8]) -> [u32; 8] {
+    // CHECK: load <8 x i32>
+    // CHECK: shl <8 x i32>
+    // CHECK: or{{( disjoint)?}} <8 x i32>
+    // CHECK: store <8 x i32>
+    x.map(|x| 2 * x + 1)
+}
+
+// This test is checking that LLVM can SRoA away a bunch of the overhead,
+// like fully moving the iterators to registers.  Notably, previous implementations
+// of `map` ended up `alloca`ing the whole `array::IntoIterator`, meaning both a
+// hard-to-eliminate `memcpy` and that the iteration counts needed to be written
+// out to stack every iteration, even for infallible operations on `Copy` types.
+//
+// This is still imperfect, as there's more copies than would be ideal,
+// but hopefully work like #103830 will improve that in future,
+// and update this test to be stricter.
+//
+// CHECK-LABEL: @long_integer_map
+#[no_mangle]
+pub fn long_integer_map(x: [u32; 512]) -> [u32; 512] {
+    // CHECK: start:
+    // CHECK-NEXT: alloca [2048 x i8]
+    // CHECK-NOT: alloca
+    // CHECK: mul <{{[0-9]+}} x i32>
+    // CHECK: add <{{[0-9]+}} x i32>
+    x.map(|x| 13 * x + 7)
+}
diff --git a/tests/codegen-llvm/array-optimized.rs b/tests/codegen-llvm/array-optimized.rs
new file mode 100644
index 00000000000..000163d5519
--- /dev/null
+++ b/tests/codegen-llvm/array-optimized.rs
@@ -0,0 +1,33 @@
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @array_copy_1_element
+#[no_mangle]
+pub fn array_copy_1_element(a: &[u8; 1], p: &mut [u8; 1]) {
+    // CHECK-NOT: alloca
+    // CHECK: %[[TEMP:.+]] = load i8, ptr %a, align 1
+    // CHECK: store i8 %[[TEMP]], ptr %p, align 1
+    // CHECK: ret
+    *p = *a;
+}
+
+// CHECK-LABEL: @array_copy_2_elements
+#[no_mangle]
+pub fn array_copy_2_elements(a: &[u8; 2], p: &mut [u8; 2]) {
+    // CHECK-NOT: alloca
+    // CHECK: %[[TEMP:.+]] = load i16, ptr %a, align 1
+    // CHECK: store i16 %[[TEMP]], ptr %p, align 1
+    // CHECK: ret
+    *p = *a;
+}
+
+// CHECK-LABEL: @array_copy_4_elements
+#[no_mangle]
+pub fn array_copy_4_elements(a: &[u8; 4], p: &mut [u8; 4]) {
+    // CHECK-NOT: alloca
+    // CHECK: %[[TEMP:.+]] = load i32, ptr %a, align 1
+    // CHECK: store i32 %[[TEMP]], ptr %p, align 1
+    // CHECK: ret
+    *p = *a;
+}
diff --git a/tests/codegen-llvm/array-repeat.rs b/tests/codegen-llvm/array-repeat.rs
new file mode 100644
index 00000000000..4c755df9390
--- /dev/null
+++ b/tests/codegen-llvm/array-repeat.rs
@@ -0,0 +1,15 @@
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+#![feature(array_repeat)]
+
+use std::array::repeat;
+
+// CHECK-LABEL: @byte_repeat
+#[no_mangle]
+fn byte_repeat(b: u8) -> [u8; 1024] {
+    // CHECK-NOT: alloca
+    // CHECK-NOT: store
+    // CHECK: memset
+    repeat(b)
+}
diff --git a/tests/codegen-llvm/ascii-char.rs b/tests/codegen-llvm/ascii-char.rs
new file mode 100644
index 00000000000..86ec9d73afe
--- /dev/null
+++ b/tests/codegen-llvm/ascii-char.rs
@@ -0,0 +1,36 @@
+//@ compile-flags: -C opt-level=1
+
+#![crate_type = "lib"]
+#![feature(ascii_char)]
+
+use std::ascii::Char as AsciiChar;
+
+// CHECK-LABEL: i8 @unwrap_digit_from_remainder(i32
+#[no_mangle]
+pub fn unwrap_digit_from_remainder(v: u32) -> AsciiChar {
+    // CHECK-NOT: icmp
+    // CHECK-NOT: panic
+
+    // CHECK: %[[R:.+]] = urem i32 %v, 10
+    // CHECK-NEXT: %[[T:.+]] = trunc{{( nuw)?( nsw)?}} i32 %[[R]] to i8
+    // CHECK-NEXT: %[[D:.+]] = or{{( disjoint)?}} i8 %[[T]], 48
+    // CHECK-NEXT: ret i8 %[[D]]
+
+    // CHECK-NOT: icmp
+    // CHECK-NOT: panic
+    AsciiChar::digit((v % 10) as u8).unwrap()
+}
+
+// CHECK-LABEL: i8 @unwrap_from_masked(i8
+#[no_mangle]
+pub fn unwrap_from_masked(b: u8) -> AsciiChar {
+    // CHECK-NOT: icmp
+    // CHECK-NOT: panic
+
+    // CHECK: %[[M:.+]] = and i8 %b, 127
+    // CHECK-NEXT: ret i8 %[[M]]
+
+    // CHECK-NOT: icmp
+    // CHECK-NOT: panic
+    AsciiChar::from_u8(b & 0x7f).unwrap()
+}
diff --git a/tests/codegen-llvm/asm/aarch64-clobbers.rs b/tests/codegen-llvm/asm/aarch64-clobbers.rs
new file mode 100644
index 00000000000..dd3ba1510b5
--- /dev/null
+++ b/tests/codegen-llvm/asm/aarch64-clobbers.rs
@@ -0,0 +1,47 @@
+//@ add-core-stubs
+//@ revisions: aarch64 aarch64_fixed_x18 aarch64_no_x18 aarch64_reserve_x18 arm64ec
+//@[aarch64] compile-flags: --target aarch64-unknown-linux-gnu
+//@[aarch64] needs-llvm-components: aarch64
+//@[aarch64_fixed_x18] compile-flags: --target aarch64-unknown-linux-gnu -Zfixed-x18
+//@[aarch64_fixed_x18] needs-llvm-components: aarch64
+//@[aarch64_no_x18] compile-flags: --target aarch64-pc-windows-msvc
+//@[aarch64_no_x18] needs-llvm-components: aarch64
+// aarch64-unknown-trusty uses aarch64-unknown-unknown-musl which doesn't
+// reserve x18 by default as llvm_target, and pass +reserve-x18 in target-spec.
+//@[aarch64_reserve_x18] compile-flags: --target aarch64-unknown-trusty
+//@[aarch64_reserve_x18] needs-llvm-components: aarch64
+//@[arm64ec] compile-flags: --target arm64ec-pc-windows-msvc
+//@[arm64ec] needs-llvm-components: aarch64
+// ignore-tidy-linelength
+
+#![crate_type = "rlib"]
+#![feature(no_core)]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+// CHECK-LABEL: @cc_clobber
+// CHECK: call void asm sideeffect "", "~{cc}"()
+#[no_mangle]
+pub unsafe fn cc_clobber() {
+    asm!("", options(nostack, nomem));
+}
+
+// CHECK-LABEL: @no_clobber
+// CHECK: call void asm sideeffect "", ""()
+#[no_mangle]
+pub unsafe fn no_clobber() {
+    asm!("", options(nostack, nomem, preserves_flags));
+}
+
+// CHECK-LABEL: @clobber_abi
+// aarch64: asm sideeffect "", "={w0},={w1},={w2},={w3},={w4},={w5},={w6},={w7},={w8},={w9},={w10},={w11},={w12},={w13},={w14},={w15},={w16},={w17},={w18},={w30},={q0},={q1},={q2},={q3},={q4},={q5},={q6},={q7},={q8},={q9},={q10},={q11},={q12},={q13},={q14},={q15},={q16},={q17},={q18},={q19},={q20},={q21},={q22},={q23},={q24},={q25},={q26},={q27},={q28},={q29},={q30},={q31},~{p0},~{p1},~{p2},~{p3},~{p4},~{p5},~{p6},~{p7},~{p8},~{p9},~{p10},~{p11},~{p12},~{p13},~{p14},~{p15},~{ffr}"()
+// aarch64_fixed_x18: asm sideeffect "", "={w0},={w1},={w2},={w3},={w4},={w5},={w6},={w7},={w8},={w9},={w10},={w11},={w12},={w13},={w14},={w15},={w16},={w17},={w30},={q0},={q1},={q2},={q3},={q4},={q5},={q6},={q7},={q8},={q9},={q10},={q11},={q12},={q13},={q14},={q15},={q16},={q17},={q18},={q19},={q20},={q21},={q22},={q23},={q24},={q25},={q26},={q27},={q28},={q29},={q30},={q31},~{p0},~{p1},~{p2},~{p3},~{p4},~{p5},~{p6},~{p7},~{p8},~{p9},~{p10},~{p11},~{p12},~{p13},~{p14},~{p15},~{ffr}"()
+// aarch64_no_x18: asm sideeffect "", "={w0},={w1},={w2},={w3},={w4},={w5},={w6},={w7},={w8},={w9},={w10},={w11},={w12},={w13},={w14},={w15},={w16},={w17},={w30},={q0},={q1},={q2},={q3},={q4},={q5},={q6},={q7},={q8},={q9},={q10},={q11},={q12},={q13},={q14},={q15},={q16},={q17},={q18},={q19},={q20},={q21},={q22},={q23},={q24},={q25},={q26},={q27},={q28},={q29},={q30},={q31},~{p0},~{p1},~{p2},~{p3},~{p4},~{p5},~{p6},~{p7},~{p8},~{p9},~{p10},~{p11},~{p12},~{p13},~{p14},~{p15},~{ffr}"()
+// aarch64_reserve_x18: asm sideeffect "", "={w0},={w1},={w2},={w3},={w4},={w5},={w6},={w7},={w8},={w9},={w10},={w11},={w12},={w13},={w14},={w15},={w16},={w17},={w30},={q0},={q1},={q2},={q3},={q4},={q5},={q6},={q7},={q8},={q9},={q10},={q11},={q12},={q13},={q14},={q15},={q16},={q17},={q18},={q19},={q20},={q21},={q22},={q23},={q24},={q25},={q26},={q27},={q28},={q29},={q30},={q31},~{p0},~{p1},~{p2},~{p3},~{p4},~{p5},~{p6},~{p7},~{p8},~{p9},~{p10},~{p11},~{p12},~{p13},~{p14},~{p15},~{ffr}"()
+// arm64ec: asm sideeffect "", "={w0},={w1},={w2},={w3},={w4},={w5},={w6},={w7},={w8},={w9},={w10},={w11},={w12},={w15},={w16},={w17},={w30},={q0},={q1},={q2},={q3},={q4},={q5},={q6},={q7},={q8},={q9},={q10},={q11},={q12},={q13},={q14},={q15}"()
+#[no_mangle]
+pub unsafe fn clobber_abi() {
+    asm!("", clobber_abi("C"), options(nostack, nomem, preserves_flags));
+}
diff --git a/tests/codegen-llvm/asm/avr-clobbers.rs b/tests/codegen-llvm/asm/avr-clobbers.rs
new file mode 100644
index 00000000000..9451127bf04
--- /dev/null
+++ b/tests/codegen-llvm/asm/avr-clobbers.rs
@@ -0,0 +1,39 @@
+//@ add-core-stubs
+//@ assembly-output: emit-asm
+//@ compile-flags: --target avr-none -C target-cpu=atmega328p
+//@ needs-llvm-components: avr
+
+#![crate_type = "rlib"]
+#![feature(no_core, asm_experimental_arch)]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+// CHECK-LABEL: @sreg_is_clobbered
+// CHECK: void asm sideeffect "", "~{sreg}"()
+#[no_mangle]
+pub unsafe fn sreg_is_clobbered() {
+    asm!("", options(nostack, nomem));
+}
+
+// CHECK-LABEL: @sreg_is_not_clobbered_if_preserve_flags_is_used
+// CHECK: void asm sideeffect "", ""()
+#[no_mangle]
+pub unsafe fn sreg_is_not_clobbered_if_preserve_flags_is_used() {
+    asm!("", options(nostack, nomem, preserves_flags));
+}
+
+// CHECK-LABEL: @clobber_abi
+// CHECK: asm sideeffect "", "={r18},={r19},={r20},={r21},={r22},={r23},={r24},={r25},={r26},={r27},={r30},={r31},~{sreg}"()
+#[no_mangle]
+pub unsafe fn clobber_abi() {
+    asm!("", clobber_abi("C"), options(nostack, nomem));
+}
+
+// CHECK-LABEL: @clobber_abi_with_preserved_flags
+// CHECK: asm sideeffect "", "={r18},={r19},={r20},={r21},={r22},={r23},={r24},={r25},={r26},={r27},={r30},={r31}"()
+#[no_mangle]
+pub unsafe fn clobber_abi_with_preserved_flags() {
+    asm!("", clobber_abi("C"), options(nostack, nomem, preserves_flags));
+}
diff --git a/tests/codegen-llvm/asm/bpf-clobbers.rs b/tests/codegen-llvm/asm/bpf-clobbers.rs
new file mode 100644
index 00000000000..1117549b1ec
--- /dev/null
+++ b/tests/codegen-llvm/asm/bpf-clobbers.rs
@@ -0,0 +1,31 @@
+//@ add-core-stubs
+//@ compile-flags: --target bpfel-unknown-none
+//@ needs-llvm-components: bpf
+
+#![crate_type = "rlib"]
+#![feature(no_core, asm_experimental_arch)]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+// CHECK-LABEL: @flags_clobber
+// CHECK: call void asm sideeffect "", ""()
+#[no_mangle]
+pub unsafe fn flags_clobber() {
+    asm!("", options(nostack, nomem));
+}
+
+// CHECK-LABEL: @no_clobber
+// CHECK: call void asm sideeffect "", ""()
+#[no_mangle]
+pub unsafe fn no_clobber() {
+    asm!("", options(nostack, nomem, preserves_flags));
+}
+
+// CHECK-LABEL: @clobber_abi
+// CHECK: asm sideeffect "", "={r0},={r1},={r2},={r3},={r4},={r5}"()
+#[no_mangle]
+pub unsafe fn clobber_abi() {
+    asm!("", clobber_abi("C"), options(nostack, nomem, preserves_flags));
+}
diff --git a/tests/codegen-llvm/asm/critical.rs b/tests/codegen-llvm/asm/critical.rs
new file mode 100644
index 00000000000..0f29d7c69b4
--- /dev/null
+++ b/tests/codegen-llvm/asm/critical.rs
@@ -0,0 +1,36 @@
+//@ only-x86_64
+//@ compile-flags: -C no-prepopulate-passes
+#![feature(asm_goto_with_outputs)]
+#![crate_type = "lib"]
+use std::arch::asm;
+
+// Regression test for #137867. Check that critical edges have been split before code generation,
+// and so all stores to the asm output occur on disjoint paths without any of them jumping to
+// another callbr label.
+//
+// CHECK-LABEL: @f(
+// CHECK:        [[OUT:%.*]] = callbr i32 asm
+// CHECK-NEXT:   to label %[[BB0:.*]] [label %[[BB1:.*]], label %[[BB2:.*]]],
+// CHECK:       [[BB1]]:
+// CHECK-NEXT:    store i32 [[OUT]], ptr %a
+// CHECK-NEXT:    br label %[[BBR:.*]]
+// CHECK:       [[BB2]]:
+// CHECK-NEXT:    store i32 [[OUT]], ptr %a
+// CHECK-NEXT:    br label %[[BBR]]
+// CHECK:       [[BB0]]:
+// CHECK-NEXT:    store i32 [[OUT]], ptr %a
+// CHECK-NEXT:    br label %[[BBR]]
+// CHECK:       [[BBR]]:
+// CHECK-NEXT:    [[RET:%.*]] = load i32, ptr %a
+// CHECK-NEXT:    ret i32 [[RET]]
+#[unsafe(no_mangle)]
+pub unsafe fn f(mut a: u32) -> u32 {
+    asm!(
+        "jmp {}
+         jmp {}",
+        label {},
+        label {},
+        inout("eax") a,
+    );
+    a
+}
diff --git a/tests/codegen-llvm/asm/csky-clobbers.rs b/tests/codegen-llvm/asm/csky-clobbers.rs
new file mode 100644
index 00000000000..4986d0fe56d
--- /dev/null
+++ b/tests/codegen-llvm/asm/csky-clobbers.rs
@@ -0,0 +1,24 @@
+//@ add-core-stubs
+//@ compile-flags: --target csky-unknown-linux-gnuabiv2
+//@ needs-llvm-components: csky
+
+#![crate_type = "rlib"]
+#![feature(no_core, asm_experimental_arch)]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+// CHECK-LABEL: @flags_clobber
+// CHECK: call void asm sideeffect "", "~{psr}"()
+#[no_mangle]
+pub unsafe fn flags_clobber() {
+    asm!("", options(nostack, nomem));
+}
+
+// CHECK-LABEL: @no_clobber
+// CHECK: call void asm sideeffect "", ""()
+#[no_mangle]
+pub unsafe fn no_clobber() {
+    asm!("", options(nostack, nomem, preserves_flags));
+}
diff --git a/tests/codegen-llvm/asm/foo.s b/tests/codegen-llvm/asm/foo.s
new file mode 100644
index 00000000000..304d82aa0c6
--- /dev/null
+++ b/tests/codegen-llvm/asm/foo.s
@@ -0,0 +1,3 @@
+.global foo
+foo:
+    jmp baz
diff --git a/tests/codegen-llvm/asm/global_asm.rs b/tests/codegen-llvm/asm/global_asm.rs
new file mode 100644
index 00000000000..32075daa3cf
--- /dev/null
+++ b/tests/codegen-llvm/asm/global_asm.rs
@@ -0,0 +1,28 @@
+//@ revisions: x32 x64
+//@[x32] only-x86
+//@[x64] only-x86_64
+//@ compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+use std::arch::global_asm;
+
+// CHECK-LABEL: foo
+// CHECK: module asm
+// this regex will capture the correct unconditional branch inst.
+// CHECK: module asm "{{[[:space:]]+}}jmp baz"
+global_asm!(
+    r#"
+    .global foo
+foo:
+    jmp baz
+"#
+);
+
+extern "C" {
+    fn foo();
+}
+
+// CHECK-LABEL: @baz
+#[no_mangle]
+pub unsafe extern "C" fn baz() {}
diff --git a/tests/codegen-llvm/asm/global_asm_include.rs b/tests/codegen-llvm/asm/global_asm_include.rs
new file mode 100644
index 00000000000..98be9c3e333
--- /dev/null
+++ b/tests/codegen-llvm/asm/global_asm_include.rs
@@ -0,0 +1,21 @@
+//@ revisions: x32 x64
+//@[x32] only-x86
+//@[x64] only-x86_64
+//@ compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+use std::arch::global_asm;
+
+// CHECK-LABEL: foo
+// CHECK: module asm
+// CHECK: module asm "{{[[:space:]]+}}jmp baz"
+global_asm!(include_str!("foo.s"));
+
+extern "C" {
+    fn foo();
+}
+
+// CHECK-LABEL: @baz
+#[no_mangle]
+pub unsafe extern "C" fn baz() {}
diff --git a/tests/codegen-llvm/asm/global_asm_x2.rs b/tests/codegen-llvm/asm/global_asm_x2.rs
new file mode 100644
index 00000000000..9e3a00f0680
--- /dev/null
+++ b/tests/codegen-llvm/asm/global_asm_x2.rs
@@ -0,0 +1,47 @@
+//@ revisions: x32 x64
+//@[x32] only-x86
+//@[x64] only-x86_64
+//@ compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+#![no_std]
+
+use core::arch::global_asm;
+
+// CHECK-LABEL: foo
+// CHECK: module asm
+// CHECK: module asm "{{[[:space:]]+}}jmp baz"
+// any other global_asm will be appended to this first block, so:
+// CHECK-LABEL: bar
+// CHECK: module asm "{{[[:space:]]+}}jmp quux"
+global_asm!(
+    r#"
+    .global foo
+foo:
+    jmp baz
+"#
+);
+
+extern "C" {
+    fn foo();
+}
+
+// CHECK-LABEL: @baz
+#[no_mangle]
+pub unsafe extern "C" fn baz() {}
+
+// no checks here; this has been appended to the first occurrence
+global_asm!(
+    r#"
+    .global bar
+bar:
+    jmp quux
+"#
+);
+
+extern "C" {
+    fn bar();
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn quux() {}
diff --git a/tests/codegen-llvm/asm/goto.rs b/tests/codegen-llvm/asm/goto.rs
new file mode 100644
index 00000000000..f68c399c920
--- /dev/null
+++ b/tests/codegen-llvm/asm/goto.rs
@@ -0,0 +1,63 @@
+//@ compile-flags: -Copt-level=3
+//@ only-x86_64
+
+#![crate_type = "rlib"]
+#![feature(asm_goto_with_outputs)]
+
+use std::arch::asm;
+
+// CHECK-LABEL: @asm_goto
+#[no_mangle]
+pub unsafe fn asm_goto() {
+    // CHECK: callbr void asm sideeffect alignstack inteldialect "
+    // CHECK-NEXT: to label %[[FALLTHROUGHBB:[a-b0-9]+]] [label %[[JUMPBB:[a-b0-9]+]]]
+    asm!("jmp {}", label {});
+}
+
+// CHECK-LABEL: @asm_goto_with_outputs
+#[no_mangle]
+pub unsafe fn asm_goto_with_outputs() -> u64 {
+    let out: u64;
+    // CHECK: [[RES:%[0-9]+]] = callbr i64 asm sideeffect alignstack inteldialect "
+    // CHECK-NEXT: to label %[[FALLTHROUGHBB:[a-b0-9]+]] [label %[[JUMPBB:[a-b0-9]+]]]
+    asm!("{} /* {} */", out(reg) out, label { return 1; });
+    // CHECK: [[JUMPBB]]:
+    // CHECK-NEXT: [[RET:%.+]] = phi i64 [ [[RES]], %[[FALLTHROUGHBB]] ], [ 1, %start ]
+    // CHECK-NEXT: ret i64 [[RET]]
+    out
+}
+
+// CHECK-LABEL: @asm_goto_with_outputs_use_in_label
+#[no_mangle]
+pub unsafe fn asm_goto_with_outputs_use_in_label() -> u64 {
+    let out: u64;
+    // CHECK: [[RES:%[0-9]+]] = callbr i64 asm sideeffect alignstack inteldialect "
+    // CHECK-NEXT: to label %[[FALLTHROUGHBB:[a-b0-9]+]] [label %[[JUMPBB:[a-b0-9]+]]]
+    asm!("{} /* {} */", out(reg) out, label { return out; });
+    // CHECK: [[JUMPBB]]:
+    // CHECK-NEXT: [[RET:%.+]] = phi i64 [ 1, %[[FALLTHROUGHBB]] ], [ [[RES]], %start ]
+    // CHECK-NEXT: ret i64 [[RET]]
+    1
+}
+
+// CHECK-LABEL: @asm_goto_noreturn
+#[no_mangle]
+pub unsafe fn asm_goto_noreturn() -> u64 {
+    // CHECK: callbr void asm sideeffect alignstack inteldialect "
+    // CHECK-NEXT: to label %unreachable [label %[[JUMPBB:[a-b0-9]+]]]
+    asm!("jmp {}", label { return 1; }, options(noreturn));
+    // CHECK: [[JUMPBB]]:
+    // CHECK-NEXT: ret i64 1
+}
+
+// CHECK-LABEL: @asm_goto_noreturn_with_outputs
+#[no_mangle]
+pub unsafe fn asm_goto_noreturn_with_outputs() -> u64 {
+    let out: u64;
+    // CHECK: [[RES:%[0-9]+]] = callbr i64 asm sideeffect alignstack inteldialect "
+    // CHECK-NEXT: to label %[[FALLTHROUGHBB:[a-b0-9]+]] [label %[[JUMPBB:[a-b0-9]+]]]
+    asm!("mov {}, 1", "jmp {}", out(reg) out, label { return out; });
+    // CHECK: [[JUMPBB]]:
+    // CHECK-NEXT: ret i64 [[RES]]
+    out
+}
diff --git a/tests/codegen-llvm/asm/hexagon-clobbers.rs b/tests/codegen-llvm/asm/hexagon-clobbers.rs
new file mode 100644
index 00000000000..800b8964669
--- /dev/null
+++ b/tests/codegen-llvm/asm/hexagon-clobbers.rs
@@ -0,0 +1,33 @@
+//@ add-core-stubs
+//@ revisions: hexagon
+//@[hexagon] compile-flags: --target hexagon-unknown-linux-musl
+//@[hexagon] needs-llvm-components: hexagon
+//@ compile-flags: -Zmerge-functions=disabled
+
+#![crate_type = "rlib"]
+#![feature(no_core, asm_experimental_arch)]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+// CHECK-LABEL: @flags_clobber
+// CHECK: call void asm sideeffect "", ""()
+#[no_mangle]
+pub unsafe fn flags_clobber() {
+    asm!("", options(nostack, nomem));
+}
+
+// CHECK-LABEL: @no_clobber
+// CHECK: call void asm sideeffect "", ""()
+#[no_mangle]
+pub unsafe fn no_clobber() {
+    asm!("", options(nostack, nomem, preserves_flags));
+}
+
+// CHECK-LABEL: @p0_clobber
+// CHECK: call void asm sideeffect "", "~{p0}"()
+#[no_mangle]
+pub unsafe fn p0_clobber() {
+    asm!("", out("p0") _, options(nostack, nomem, preserves_flags));
+}
diff --git a/tests/codegen-llvm/asm/may_unwind.rs b/tests/codegen-llvm/asm/may_unwind.rs
new file mode 100644
index 00000000000..63cdec7584c
--- /dev/null
+++ b/tests/codegen-llvm/asm/may_unwind.rs
@@ -0,0 +1,39 @@
+//@ compile-flags: -Copt-level=3
+//@ only-x86_64
+
+#![crate_type = "rlib"]
+#![feature(asm_unwind)]
+
+use std::arch::asm;
+
+#[no_mangle]
+pub extern "C" fn panicky() {}
+
+struct Foo;
+
+impl Drop for Foo {
+    fn drop(&mut self) {
+        println!();
+    }
+}
+
+// CHECK-LABEL: @asm_may_unwind
+#[no_mangle]
+pub unsafe fn asm_may_unwind() {
+    let _m = Foo;
+    // CHECK: invoke void asm sideeffect alignstack inteldialect unwind ""
+    asm!("", options(may_unwind));
+}
+
+// CHECK-LABEL: @asm_with_result_may_unwind
+#[no_mangle]
+pub unsafe fn asm_with_result_may_unwind() -> u64 {
+    let _m = Foo;
+    let res: u64;
+    // CHECK: [[RES:%[0-9]+]] = invoke i64 asm sideeffect alignstack inteldialect unwind
+    // CHECK-NEXT: to label %[[NORMALBB:[a-b0-9]+]]
+    asm!("mov {}, 1", out(reg) res, options(may_unwind));
+    // CHECK: [[NORMALBB]]:
+    // CHECK: ret i64 [[RES:%[0-9]+]]
+    res
+}
diff --git a/tests/codegen-llvm/asm/maybe-uninit.rs b/tests/codegen-llvm/asm/maybe-uninit.rs
new file mode 100644
index 00000000000..d76d5cb1312
--- /dev/null
+++ b/tests/codegen-llvm/asm/maybe-uninit.rs
@@ -0,0 +1,27 @@
+//@ compile-flags: -Copt-level=3
+//@ only-x86_64
+
+#![crate_type = "rlib"]
+#![allow(asm_sub_register)]
+
+use std::arch::asm;
+use std::mem::MaybeUninit;
+
+// CHECK-LABEL: @int
+#[no_mangle]
+pub unsafe fn int(x: MaybeUninit<i32>) -> MaybeUninit<i32> {
+    let y: MaybeUninit<i32>;
+    asm!("/*{}{}*/", in(reg) x, out(reg) y);
+    y
+}
+
+// CHECK-LABEL: @inout
+#[no_mangle]
+pub unsafe fn inout(mut x: i32) -> MaybeUninit<u32> {
+    let mut y: MaybeUninit<u32>;
+    asm!("/*{}*/", inout(reg) x => y);
+    asm!("/*{}*/", inout(reg) y => x);
+    asm!("/*{}*/", inlateout(reg) x => y);
+    asm!("/*{}*/", inlateout(reg) y => x);
+    y
+}
diff --git a/tests/codegen-llvm/asm/msp430-clobbers.rs b/tests/codegen-llvm/asm/msp430-clobbers.rs
new file mode 100644
index 00000000000..2c8d29cffc4
--- /dev/null
+++ b/tests/codegen-llvm/asm/msp430-clobbers.rs
@@ -0,0 +1,32 @@
+//@ add-core-stubs
+//@ assembly-output: emit-asm
+//@ compile-flags: --target msp430-none-elf
+//@ needs-llvm-components: msp430
+
+#![crate_type = "rlib"]
+#![feature(no_core, asm_experimental_arch)]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+// CHECK-LABEL: @sr_clobber
+// CHECK: call void asm sideeffect "", "~{sr}"()
+#[no_mangle]
+pub unsafe fn sr_clobber() {
+    asm!("", options(nostack, nomem));
+}
+
+// CHECK-LABEL: @no_clobber
+// CHECK: call void asm sideeffect "", ""()
+#[no_mangle]
+pub unsafe fn no_clobber() {
+    asm!("", options(nostack, nomem, preserves_flags));
+}
+
+// CHECK-LABEL: @clobber_abi
+// CHECK: asm sideeffect "", "={r11},={r12},={r13},={r14},={r15}"()
+#[no_mangle]
+pub unsafe fn clobber_abi() {
+    asm!("", clobber_abi("C"), options(nostack, nomem, preserves_flags));
+}
diff --git a/tests/codegen-llvm/asm/multiple-options.rs b/tests/codegen-llvm/asm/multiple-options.rs
new file mode 100644
index 00000000000..4d87471a193
--- /dev/null
+++ b/tests/codegen-llvm/asm/multiple-options.rs
@@ -0,0 +1,54 @@
+//@ compile-flags: -Copt-level=3
+//@ only-x86_64
+
+#![crate_type = "rlib"]
+
+use std::arch::asm;
+
+// CHECK-LABEL: @pure
+// CHECK-NOT: asm
+// CHECK: ret void
+#[no_mangle]
+pub unsafe fn pure(x: i32) {
+    let y: i32;
+    asm!("", out("ax") y, in("cx") x, options(pure), options(nomem));
+}
+
+pub static mut VAR: i32 = 0;
+pub static mut DUMMY_OUTPUT: i32 = 0;
+
+// CHECK-LABEL: @readonly
+// CHECK: call i32 asm
+// CHECK: ret i32 1
+#[no_mangle]
+pub unsafe fn readonly() -> i32 {
+    VAR = 1;
+    asm!("", out("ax") DUMMY_OUTPUT, options(pure), options(readonly));
+    VAR
+}
+
+// CHECK-LABEL: @nomem
+// CHECK-NOT: store
+// CHECK: call i32 asm
+// CHECK: store
+// CHECK: ret i32 2
+#[no_mangle]
+pub unsafe fn nomem() -> i32 {
+    VAR = 1;
+    asm!("", out("ax") DUMMY_OUTPUT, options(pure), options(nomem));
+    VAR = 2;
+    VAR
+}
+
+// CHECK-LABEL: @not_nomem
+// CHECK: store
+// CHECK: call i32 asm
+// CHECK: store
+// CHECK: ret i32 2
+#[no_mangle]
+pub unsafe fn not_nomem() -> i32 {
+    VAR = 1;
+    asm!("", out("ax") DUMMY_OUTPUT, options(pure), options(readonly));
+    VAR = 2;
+    VAR
+}
diff --git a/tests/codegen-llvm/asm/options.rs b/tests/codegen-llvm/asm/options.rs
new file mode 100644
index 00000000000..c087f91fd43
--- /dev/null
+++ b/tests/codegen-llvm/asm/options.rs
@@ -0,0 +1,104 @@
+//@ compile-flags: -Copt-level=3
+//@ only-x86_64
+
+#![crate_type = "rlib"]
+
+use std::arch::asm;
+
+// CHECK-LABEL: @pure
+// CHECK-NOT: asm
+// CHECK: ret void
+#[no_mangle]
+pub unsafe fn pure(x: i32) {
+    let y: i32;
+    asm!("", out("ax") y, in("cx") x, options(pure, nomem));
+}
+
+// CHECK-LABEL: @noreturn
+// CHECK: call void asm
+// CHECK-NEXT: unreachable
+#[no_mangle]
+pub unsafe fn noreturn() {
+    asm!("", options(noreturn));
+}
+
+pub static mut VAR: i32 = 0;
+pub static mut DUMMY_OUTPUT: i32 = 0;
+
+// CHECK-LABEL: @readonly
+// CHECK: call i32 asm
+// CHECK: ret i32 1
+#[no_mangle]
+pub unsafe fn readonly() -> i32 {
+    VAR = 1;
+    asm!("", out("ax") DUMMY_OUTPUT, options(pure, readonly));
+    VAR
+}
+
+// CHECK-LABEL: @not_readonly
+// CHECK: call i32 asm
+// CHECK: ret i32 %
+#[no_mangle]
+pub unsafe fn not_readonly() -> i32 {
+    VAR = 1;
+    asm!("", out("ax") DUMMY_OUTPUT, options());
+    VAR
+}
+
+// CHECK-LABEL: @nomem
+// CHECK-NOT: store
+// CHECK: call i32 asm
+// CHECK: store
+// CHECK: ret i32 2
+#[no_mangle]
+pub unsafe fn nomem() -> i32 {
+    VAR = 1;
+    asm!("", out("ax") DUMMY_OUTPUT, options(pure, nomem));
+    VAR = 2;
+    VAR
+}
+
+// CHECK-LABEL: @nomem_nopure
+// CHECK-NOT: store
+// CHECK: call i32 asm
+// CHECK: store
+// CHECK: ret i32 2
+#[no_mangle]
+pub unsafe fn nomem_nopure() -> i32 {
+    VAR = 1;
+    asm!("", out("ax") DUMMY_OUTPUT, options(nomem));
+    VAR = 2;
+    VAR
+}
+
+// CHECK-LABEL: @not_nomem
+// CHECK: store
+// CHECK: call i32 asm
+// CHECK: store
+// CHECK: ret i32 2
+#[no_mangle]
+pub unsafe fn not_nomem() -> i32 {
+    VAR = 1;
+    asm!("", out("ax") DUMMY_OUTPUT, options(pure, readonly));
+    VAR = 2;
+    VAR
+}
+
+// CHECK-LABEL: @dont_remove_nonpure
+// CHECK: call void asm
+// CHECK: call void asm
+// CHECK: call void asm
+// CHECK: ret void
+#[no_mangle]
+pub unsafe fn dont_remove_nonpure() {
+    asm!("", options());
+    asm!("", options(nomem));
+    asm!("", options(readonly));
+}
+
+// CHECK-LABEL: @raw
+// CHECK: call void asm sideeffect inteldialect "{} {}", ""()
+#[no_mangle]
+pub unsafe fn raw() {
+    asm!("{} {}", options(nostack, nomem, preserves_flags, raw));
+}
diff --git a/tests/codegen-llvm/asm/powerpc-clobbers.rs b/tests/codegen-llvm/asm/powerpc-clobbers.rs
new file mode 100644
index 00000000000..f7fc7eea5d5
--- /dev/null
+++ b/tests/codegen-llvm/asm/powerpc-clobbers.rs
@@ -0,0 +1,68 @@
+//@ add-core-stubs
+//@ revisions: powerpc powerpc64 powerpc64le aix64
+//@[powerpc] compile-flags: --target powerpc-unknown-linux-gnu
+//@[powerpc] needs-llvm-components: powerpc
+//@[powerpc64] compile-flags: --target powerpc64-unknown-linux-gnu
+//@[powerpc64] needs-llvm-components: powerpc
+//@[powerpc64le] compile-flags: --target powerpc64le-unknown-linux-gnu
+//@[powerpc64le] needs-llvm-components: powerpc
+//@[aix64] compile-flags: --target powerpc64-ibm-aix
+//@[aix64] needs-llvm-components: powerpc
+// ignore-tidy-linelength
+
+#![crate_type = "rlib"]
+#![feature(no_core, asm_experimental_arch)]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+// CHECK-LABEL: @cr_clobber
+// CHECK: call void asm sideeffect "", "~{cr}"()
+#[no_mangle]
+pub unsafe fn cr_clobber() {
+    asm!("", out("cr") _, options(nostack, nomem, preserves_flags));
+}
+
+// CHECK-LABEL: @cr0_clobber
+// CHECK: call void asm sideeffect "", "~{cr0}"()
+#[no_mangle]
+pub unsafe fn cr0_clobber() {
+    asm!("", out("cr0") _, options(nostack, nomem, preserves_flags));
+}
+
+// CHECK-LABEL: @cr5_clobber
+// CHECK: call void asm sideeffect "", "~{cr5}"()
+#[no_mangle]
+pub unsafe fn cr5_clobber() {
+    asm!("", out("cr5") _, options(nostack, nomem, preserves_flags));
+}
+
+// CHECK-LABEL: @xer_clobber
+// CHECK: call void asm sideeffect "", "~{xer}"()
+#[no_mangle]
+pub unsafe fn xer_clobber() {
+    asm!("", out("xer") _, options(nostack, nomem, preserves_flags));
+}
+
+// Output format depends on the availability of altivec.
+// CHECK-LABEL: @v0_clobber
+// powerpc: call void asm sideeffect "", "~{v0}"()
+// powerpc64: call <4 x i32> asm sideeffect "", "=&{v0}"()
+// powerpc64le: call <4 x i32> asm sideeffect "", "=&{v0}"()
+// aix64: call <4 x i32> asm sideeffect "", "=&{v0}"()
+#[no_mangle]
+pub unsafe fn v0_clobber() {
+    asm!("", out("v0") _, options(nostack, nomem, preserves_flags));
+}
+
+// Output format depends on the availability of altivec.
+// CHECK-LABEL: @clobber_abi
+// powerpc: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},~{v0},~{v1},~{v2},~{v3},~{v4},~{v5},~{v6},~{v7},~{v8},~{v9},~{v10},~{v11},~{v12},~{v13},~{v14},~{v15},~{v16},~{v17},~{v18},~{v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{xer}"()
+// powerpc64: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={v0},={v1},={v2},={v3},={v4},={v5},={v6},={v7},={v8},={v9},={v10},={v11},={v12},={v13},={v14},={v15},={v16},={v17},={v18},={v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{xer}"()
+// powerpc64le: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={v0},={v1},={v2},={v3},={v4},={v5},={v6},={v7},={v8},={v9},={v10},={v11},={v12},={v13},={v14},={v15},={v16},={v17},={v18},={v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{xer}"()
+// aix64: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={v0},={v1},={v2},={v3},={v4},={v5},={v6},={v7},={v8},={v9},={v10},={v11},={v12},={v13},={v14},={v15},={v16},={v17},={v18},={v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{xer}"()
+#[no_mangle]
+pub unsafe fn clobber_abi() {
+    asm!("", clobber_abi("C"), options(nostack, nomem, preserves_flags));
+}
diff --git a/tests/codegen-llvm/asm/riscv-clobbers.rs b/tests/codegen-llvm/asm/riscv-clobbers.rs
new file mode 100644
index 00000000000..e55b6731098
--- /dev/null
+++ b/tests/codegen-llvm/asm/riscv-clobbers.rs
@@ -0,0 +1,40 @@
+//@ add-core-stubs
+//@ assembly-output: emit-asm
+//@ revisions: rv32i rv64i rv32e
+//@[rv32i] compile-flags: --target riscv32i-unknown-none-elf
+//@[rv32i] needs-llvm-components: riscv
+//@[rv64i] compile-flags: --target riscv64imac-unknown-none-elf
+//@[rv64i] needs-llvm-components: riscv
+//@[rv32e] compile-flags: --target riscv32e-unknown-none-elf
+//@[rv32e] needs-llvm-components: riscv
+// ignore-tidy-linelength
+
+#![crate_type = "rlib"]
+#![feature(no_core)]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+// CHECK-LABEL: @flags_clobber
+// CHECK: call void asm sideeffect "", "~{vtype},~{vl},~{vxsat},~{vxrm}"()
+#[no_mangle]
+pub unsafe fn flags_clobber() {
+    asm!("", options(nostack, nomem));
+}
+
+// CHECK-LABEL: @no_clobber
+// CHECK: call void asm sideeffect "", ""()
+#[no_mangle]
+pub unsafe fn no_clobber() {
+    asm!("", options(nostack, nomem, preserves_flags));
+}
+
+// CHECK-LABEL: @clobber_abi
+// rv32i: asm sideeffect "", "={x1},={x5},={x6},={x7},={x10},={x11},={x12},={x13},={x14},={x15},={x16},={x17},={x28},={x29},={x30},={x31},~{f0},~{f1},~{f2},~{f3},~{f4},~{f5},~{f6},~{f7},~{f10},~{f11},~{f12},~{f13},~{f14},~{f15},~{f16},~{f17},~{f28},~{f29},~{f30},~{f31},~{v0},~{v1},~{v2},~{v3},~{v4},~{v5},~{v6},~{v7},~{v8},~{v9},~{v10},~{v11},~{v12},~{v13},~{v14},~{v15},~{v16},~{v17},~{v18},~{v19},~{v20},~{v21},~{v22},~{v23},~{v24},~{v25},~{v26},~{v27},~{v28},~{v29},~{v30},~{v31}"()
+// rv64i: asm sideeffect "", "={x1},={x5},={x6},={x7},={x10},={x11},={x12},={x13},={x14},={x15},={x16},={x17},={x28},={x29},={x30},={x31},~{f0},~{f1},~{f2},~{f3},~{f4},~{f5},~{f6},~{f7},~{f10},~{f11},~{f12},~{f13},~{f14},~{f15},~{f16},~{f17},~{f28},~{f29},~{f30},~{f31},~{v0},~{v1},~{v2},~{v3},~{v4},~{v5},~{v6},~{v7},~{v8},~{v9},~{v10},~{v11},~{v12},~{v13},~{v14},~{v15},~{v16},~{v17},~{v18},~{v19},~{v20},~{v21},~{v22},~{v23},~{v24},~{v25},~{v26},~{v27},~{v28},~{v29},~{v30},~{v31}"()
+// rv32e: asm sideeffect "", "={x1},={x5},={x6},={x7},={x10},={x11},={x12},={x13},={x14},={x15},~{f0},~{f1},~{f2},~{f3},~{f4},~{f5},~{f6},~{f7},~{f10},~{f11},~{f12},~{f13},~{f14},~{f15},~{f16},~{f17},~{f28},~{f29},~{f30},~{f31},~{v0},~{v1},~{v2},~{v3},~{v4},~{v5},~{v6},~{v7},~{v8},~{v9},~{v10},~{v11},~{v12},~{v13},~{v14},~{v15},~{v16},~{v17},~{v18},~{v19},~{v20},~{v21},~{v22},~{v23},~{v24},~{v25},~{v26},~{v27},~{v28},~{v29},~{v30},~{v31}"()
+#[no_mangle]
+pub unsafe fn clobber_abi() {
+    asm!("", clobber_abi("C"), options(nostack, nomem, preserves_flags));
+}
diff --git a/tests/codegen-llvm/asm/s390x-clobbers.rs b/tests/codegen-llvm/asm/s390x-clobbers.rs
new file mode 100644
index 00000000000..0ba22a32abf
--- /dev/null
+++ b/tests/codegen-llvm/asm/s390x-clobbers.rs
@@ -0,0 +1,46 @@
+//@ add-core-stubs
+//@ revisions: s390x
+//@[s390x] compile-flags: --target s390x-unknown-linux-gnu -C target-cpu=z10
+//@[s390x] needs-llvm-components: systemz
+
+#![crate_type = "rlib"]
+#![feature(no_core)]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+// CHECK-LABEL: @cc_clobber
+// CHECK: call void asm sideeffect "", "~{cc}"()
+#[no_mangle]
+pub unsafe fn cc_clobber() {
+    asm!("", options(nostack, nomem));
+}
+
+// CHECK-LABEL: @no_clobber
+// CHECK: call void asm sideeffect "", ""()
+#[no_mangle]
+pub unsafe fn no_clobber() {
+    asm!("", options(nostack, nomem, preserves_flags));
+}
+
+// CHECK-LABEL: @a2_clobber
+// CHECK: call void asm sideeffect "", "~{a2}"()
+#[no_mangle]
+pub unsafe fn a2_clobber() {
+    asm!("", out("a2") _, options(nostack, nomem, preserves_flags));
+}
+
+// CHECK-LABEL: @v0_clobber
+// CHECK: call void asm sideeffect "", "~{v0}"()
+#[no_mangle]
+pub unsafe fn v0_clobber() {
+    asm!("", out("v0") _, options(nostack, nomem, preserves_flags));
+}
+
+// CHECK-LABEL: @clobber_abi
+// CHECK: asm sideeffect "", "={r0},={r1},={r2},={r3},={r4},={r5},={r14},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},~{v0},~{v1},~{v2},~{v3},~{v4},~{v5},~{v6},~{v7},~{v8},~{v9},~{v10},~{v11},~{v12},~{v13},~{v14},~{v15},~{v16},~{v17},~{v18},~{v19},~{v20},~{v21},~{v22},~{v23},~{v24},~{v25},~{v26},~{v27},~{v28},~{v29},~{v30},~{v31},~{a2},~{a3},~{a4},~{a5},~{a6},~{a7},~{a8},~{a9},~{a10},~{a11},~{a12},~{a13},~{a14},~{a15}"()
+#[no_mangle]
+pub unsafe fn clobber_abi() {
+    asm!("", clobber_abi("C"), options(nostack, nomem, preserves_flags));
+}
diff --git a/tests/codegen-llvm/asm/sanitize-llvm.rs b/tests/codegen-llvm/asm/sanitize-llvm.rs
new file mode 100644
index 00000000000..97a77033284
--- /dev/null
+++ b/tests/codegen-llvm/asm/sanitize-llvm.rs
@@ -0,0 +1,24 @@
+//@ add-core-stubs
+// FIXME(nagisa): remove the flags below once all targets support `asm!`.
+//@ compile-flags: --target x86_64-unknown-linux-gnu -Copt-level=0
+//@ needs-llvm-components: x86
+
+// Verify we sanitize the special tokens for the LLVM inline-assembly, ensuring people won't
+// inadvertently rely on the LLVM-specific syntax and features.
+#![no_core]
+#![feature(no_core)]
+#![crate_type = "rlib"]
+#![allow(named_asm_labels)]
+
+extern crate minicore;
+use minicore::*;
+
+pub unsafe fn we_escape_dollar_signs() {
+    // CHECK: call void asm sideeffect alignstack inteldialect "banana$$:"
+    asm!(r"banana$:",)
+}
+
+pub unsafe fn we_escape_escapes_too() {
+    // CHECK: call void asm sideeffect alignstack inteldialect "banana\{{(\\|5C)}}36:"
+    asm!(r"banana\36:",)
+}
diff --git a/tests/codegen-llvm/asm/sparc-clobbers.rs b/tests/codegen-llvm/asm/sparc-clobbers.rs
new file mode 100644
index 00000000000..a71715ed94d
--- /dev/null
+++ b/tests/codegen-llvm/asm/sparc-clobbers.rs
@@ -0,0 +1,36 @@
+//@ add-core-stubs
+//@ revisions: sparc sparcv8plus sparc64
+//@[sparc] compile-flags: --target sparc-unknown-none-elf
+//@[sparc] needs-llvm-components: sparc
+//@[sparcv8plus] compile-flags: --target sparc-unknown-linux-gnu
+//@[sparcv8plus] needs-llvm-components: sparc
+//@[sparc64] compile-flags: --target sparc64-unknown-linux-gnu
+//@[sparc64] needs-llvm-components: sparc
+
+#![crate_type = "rlib"]
+#![feature(no_core, asm_experimental_arch)]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+// CHECK-LABEL: @cc_clobber
+// CHECK: call void asm sideeffect "", "~{icc},~{fcc0},~{fcc1},~{fcc2},~{fcc3}"()
+#[no_mangle]
+pub unsafe fn cc_clobber() {
+    asm!("", options(nostack, nomem));
+}
+
+// CHECK-LABEL: @no_clobber
+// CHECK: call void asm sideeffect "", ""()
+#[no_mangle]
+pub unsafe fn no_clobber() {
+    asm!("", options(nostack, nomem, preserves_flags));
+}
+
+// CHECK-LABEL: @y_clobber
+// CHECK: call void asm sideeffect "", "~{y}"()
+#[no_mangle]
+pub unsafe fn y_clobber() {
+    asm!("", out("y") _, options(nostack, nomem, preserves_flags));
+}
diff --git a/tests/codegen-llvm/asm/x86-clobber_abi.rs b/tests/codegen-llvm/asm/x86-clobber_abi.rs
new file mode 100644
index 00000000000..5b34b4e8ef3
--- /dev/null
+++ b/tests/codegen-llvm/asm/x86-clobber_abi.rs
@@ -0,0 +1,36 @@
+//@ compile-flags: -Copt-level=3
+//@ only-x86_64
+
+#![crate_type = "rlib"]
+
+use std::arch::asm;
+
+// CHECK-LABEL: @clobber_sysv64
+// CHECK: ={ax},={cx},={dx},={si},={di},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k0},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{tmm0},~{tmm1},~{tmm2},~{tmm3},~{tmm4},~{tmm5},~{tmm6},~{tmm7},~{dirflag},~{fpsr},~{flags},~{memory}
+#[no_mangle]
+pub unsafe fn clobber_sysv64() {
+    asm!("", clobber_abi("sysv64"));
+}
+
+// CHECK-LABEL: @clobber_win64
+// CHECK: ={ax},={cx},={dx},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k0},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{tmm0},~{tmm1},~{tmm2},~{tmm3},~{tmm4},~{tmm5},~{tmm6},~{tmm7},~{dirflag},~{fpsr},~{flags},~{memory}
+#[no_mangle]
+pub unsafe fn clobber_win64() {
+    asm!("", clobber_abi("win64"));
+}
+
+// CHECK-LABEL: @clobber_sysv64
+// CHECK: =&{dx},={ax},={cx},={si},={di},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k0},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{tmm0},~{tmm1},~{tmm2},~{tmm3},~{tmm4},~{tmm5},~{tmm6},~{tmm7},~{dirflag},~{fpsr},~{flags},~{memory}
+#[no_mangle]
+pub unsafe fn clobber_sysv64_edx() {
+    let foo: i32;
+    asm!("", out("edx") foo, clobber_abi("sysv64"));
+}
+
+// CHECK-LABEL: @clobber_win64
+// CHECK: =&{dx},={ax},={cx},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k0},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{tmm0},~{tmm1},~{tmm2},~{tmm3},~{tmm4},~{tmm5},~{tmm6},~{tmm7},~{dirflag},~{fpsr},~{flags},~{memory}
+#[no_mangle]
+pub unsafe fn clobber_win64_edx() {
+    let foo: i32;
+    asm!("", out("edx") foo, clobber_abi("win64"));
+}
diff --git a/tests/codegen-llvm/asm/x86-clobbers.rs b/tests/codegen-llvm/asm/x86-clobbers.rs
new file mode 100644
index 00000000000..50163b646b2
--- /dev/null
+++ b/tests/codegen-llvm/asm/x86-clobbers.rs
@@ -0,0 +1,20 @@
+//@ compile-flags: -Copt-level=3
+//@ only-x86_64
+
+#![crate_type = "rlib"]
+
+use std::arch::asm;
+
+// CHECK-LABEL: @x87_clobber
+// CHECK: ~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)}
+#[no_mangle]
+pub unsafe fn x87_clobber() {
+    asm!("foo", out("st") _);
+}
+
+// CHECK-LABEL: @mmx_clobber
+// CHECK: ~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)}
+#[no_mangle]
+pub unsafe fn mmx_clobber() {
+    asm!("bar", out("mm0") _, out("mm1") _);
+}
diff --git a/tests/codegen-llvm/asm/x86-target-clobbers.rs b/tests/codegen-llvm/asm/x86-target-clobbers.rs
new file mode 100644
index 00000000000..119372491ff
--- /dev/null
+++ b/tests/codegen-llvm/asm/x86-target-clobbers.rs
@@ -0,0 +1,29 @@
+//@ only-x86_64
+//@ revisions: base avx512
+//@ [avx512]compile-flags: -C target-feature=+avx512f
+
+#![crate_type = "rlib"]
+
+use std::arch::asm;
+
+// CHECK-LABEL: @amx_clobber
+// base: call void asm sideeffect inteldialect "", "~{tmm0}"()
+#[no_mangle]
+pub unsafe fn amx_clobber() {
+    asm!("", out("tmm0") _, options(nostack, nomem, preserves_flags));
+}
+
+// CHECK-LABEL: @avx512_clobber
+// base: call void asm sideeffect inteldialect "", "~{xmm31}"()
+// avx512: call float asm sideeffect inteldialect "", "=&{xmm31}"()
+#[no_mangle]
+pub unsafe fn avx512_clobber() {
+    asm!("", out("zmm31") _, options(nostack, nomem, preserves_flags));
+}
+
+// CHECK-LABEL: @eax_clobber
+// CHECK: call i32 asm sideeffect inteldialect "", "=&{ax}"()
+#[no_mangle]
+pub unsafe fn eax_clobber() {
+    asm!("", out("eax") _, options(nostack, nomem, preserves_flags));
+}
diff --git a/tests/codegen-llvm/assign-desugar-debuginfo.rs b/tests/codegen-llvm/assign-desugar-debuginfo.rs
new file mode 100644
index 00000000000..77ee8758b3b
--- /dev/null
+++ b/tests/codegen-llvm/assign-desugar-debuginfo.rs
@@ -0,0 +1,18 @@
+//@ compile-flags: -g -Zmir-opt-level=0
+
+#![crate_type = "lib"]
+
+#[inline(never)]
+fn swizzle(a: u32, b: u32, c: u32) -> (u32, (u32, u32)) {
+    (b, (c, a))
+}
+
+pub fn work() {
+    let mut a = 1;
+    let mut b = 2;
+    let mut c = 3;
+    (a, (b, c)) = swizzle(a, b, c);
+    println!("{a} {b} {c}");
+}
+
+// CHECK-NOT: !DILocalVariable(name: "lhs",
diff --git a/tests/codegen-llvm/async-closure-debug.rs b/tests/codegen-llvm/async-closure-debug.rs
new file mode 100644
index 00000000000..b5b369e6e54
--- /dev/null
+++ b/tests/codegen-llvm/async-closure-debug.rs
@@ -0,0 +1,20 @@
+// Just make sure that async closures don't ICE.
+//
+//@ compile-flags: -C debuginfo=2
+//@ edition: 2018
+//@ ignore-msvc
+
+// CHECK-DAG:  [[GEN_FN:!.*]] = !DINamespace(name: "async_closure_test"
+// CHECK-DAG:  [[CLOSURE:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "{closure_env#0}", scope: [[GEN_FN]]
+// CHECK-DAG:  [[UPVAR:!.*]] = !DIDerivedType(tag: DW_TAG_member, name: "upvar", scope: [[CLOSURE]]
+
+fn async_closure_test(upvar: &str) -> impl AsyncFn() + '_ {
+    async move || {
+        let hello = String::from("hello");
+        println!("{hello}, {upvar}");
+    }
+}
+
+fn main() {
+    let _async_closure = async_closure_test("world");
+}
diff --git a/tests/codegen-llvm/async-fn-debug-awaitee-field.rs b/tests/codegen-llvm/async-fn-debug-awaitee-field.rs
new file mode 100644
index 00000000000..50860c90662
--- /dev/null
+++ b/tests/codegen-llvm/async-fn-debug-awaitee-field.rs
@@ -0,0 +1,28 @@
+// ignore-tidy-linelength
+//! This test makes sure that the coroutine field capturing the awaitee in a `.await` expression
+//! is called `__awaitee` in debuginfo. This name must not be changed since debuggers and debugger
+//! extensions rely on the field having this name.
+
+//@ revisions: MSVC NONMSVC
+//@[MSVC] only-msvc
+//@[NONMSVC] ignore-msvc
+
+//@ compile-flags: -C debuginfo=2 -Copt-level=0
+//@ edition: 2018
+
+#![crate_type = "lib"]
+
+pub async fn async_fn_test() {
+    foo().await;
+}
+
+pub async fn foo() {}
+
+// NONMSVC: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}", scope: [[GEN_SCOPE:![0-9]*]],
+// MSVC: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "enum2$<async_fn_debug_awaitee_field::async_fn_test::async_fn_env$0>",
+// NONMSVC: [[GEN_SCOPE:!.*]] = !DINamespace(name: "async_fn_test",
+// CHECK: [[SUSPEND_STRUCT:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend0", scope: [[GEN]],
+// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "__awaitee", scope: [[SUSPEND_STRUCT]], {{.*}}, baseType: [[AWAITEE_TYPE:![0-9]*]],
+// NONMSVC: [[AWAITEE_TYPE]] = !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}", scope: [[AWAITEE_SCOPE:![0-9]*]],
+// MSVC: [[AWAITEE_TYPE]] = !DICompositeType(tag: DW_TAG_union_type, name: "enum2$<async_fn_debug_awaitee_field::foo::async_fn_env$0>",
+// NONMSVC: [[AWAITEE_SCOPE]] = !DINamespace(name: "foo",
diff --git a/tests/codegen-llvm/async-fn-debug-msvc.rs b/tests/codegen-llvm/async-fn-debug-msvc.rs
new file mode 100644
index 00000000000..e0c601146f8
--- /dev/null
+++ b/tests/codegen-llvm/async-fn-debug-msvc.rs
@@ -0,0 +1,55 @@
+// Verify debuginfo for coroutines:
+//  - Each variant points to the file and line of its yield point
+//  - The discriminants are marked artificial
+//  - Other fields are not marked artificial
+//
+//
+//@ compile-flags: -C debuginfo=2
+//@ edition: 2018
+//@ only-msvc
+
+async fn foo() {}
+async fn async_fn_test() {
+    foo().await;
+    let s = String::from("foo");
+    foo().await;
+}
+
+// FIXME: No way to reliably check the filename.
+
+// CHECK-DAG:  [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "enum2$<async_fn_debug_msvc::async_fn_test::async_fn_env$0>",
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant0", scope: [[GEN]],
+// For brevity, we only check the struct name and members of the last variant.
+// CHECK-SAME: file: [[FILE:![0-9]*]], line: 12,
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant1", scope: [[GEN]],
+// CHECK-SAME: file: [[FILE]], line: 16,
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant2", scope: [[GEN]],
+// CHECK-SAME: file: [[FILE]], line: 16,
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant3", scope: [[GEN]],
+// CHECK-SAME: file: [[FILE]], line: 13,
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant4", scope: [[GEN]],
+// CHECK-SAME: file: [[FILE]], line: 15,
+// CHECK-SAME: baseType: [[VARIANT_WRAPPER:![0-9]*]]
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "value", scope: [[VARIANT_WRAPPER]], file: !2, baseType: [[VARIANT:![0-9]*]],
+// CHECK:      [[VARIANT]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN]],
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[VARIANT]]
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "tag", scope: [[GEN]],
+// CHECK-NOT: flags: DIFlagArtificial
+
+fn main() {
+    let _dummy = async_fn_test();
+}
diff --git a/tests/codegen-llvm/async-fn-debug.rs b/tests/codegen-llvm/async-fn-debug.rs
new file mode 100644
index 00000000000..ed704c7cc8b
--- /dev/null
+++ b/tests/codegen-llvm/async-fn-debug.rs
@@ -0,0 +1,59 @@
+// Verify debuginfo for async fn:
+//  - Each variant points to the file and line of its yield point
+//  - The discriminants are marked artificial
+//  - Other fields are not marked artificial
+//
+//
+//@ compile-flags: -C debuginfo=2
+//@ edition: 2018
+//@ ignore-msvc
+
+async fn foo() {}
+async fn async_fn_test() {
+    foo().await;
+    let s = String::from("foo");
+    foo().await;
+}
+
+// FIXME: No way to reliably check the filename.
+
+// CHECK-DAG:  [[ASYNC_FN:!.*]] = !DINamespace(name: "async_fn_test"
+// CHECK-DAG:  [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}", scope: [[ASYNC_FN]]
+// CHECK:      [[VARIANT:!.*]] = !DICompositeType(tag: DW_TAG_variant_part, scope: [[GEN]],
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: discriminator: [[DISC:![0-9]*]]
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "0", scope: [[VARIANT]],
+// CHECK-SAME: file: [[FILE:![0-9]*]], line: 12,
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
+// CHECK:      {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "Unresumed", scope: [[GEN]],
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "1", scope: [[VARIANT]],
+// CHECK-SAME: file: [[FILE]], line: 16,
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "2", scope: [[VARIANT]],
+// CHECK-SAME: file: [[FILE]], line: 16,
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "3", scope: [[VARIANT]],
+// CHECK-SAME: file: [[FILE]], line: 13,
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "4", scope: [[VARIANT]],
+// CHECK-SAME: file: [[FILE]], line: 15,
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
+// CHECK:      [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN]],
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[S1]]
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
+// CHECK:      [[DISC]] = !DIDerivedType(tag: DW_TAG_member, name: "__state", scope: [[GEN]],
+// CHECK-SAME: flags: DIFlagArtificial
+
+fn main() {
+    let _dummy = async_fn_test();
+}
diff --git a/tests/codegen-llvm/atomic-operations.rs b/tests/codegen-llvm/atomic-operations.rs
new file mode 100644
index 00000000000..8771b8b2419
--- /dev/null
+++ b/tests/codegen-llvm/atomic-operations.rs
@@ -0,0 +1,84 @@
+// Code generation of atomic operations.
+//@ compile-flags: -Copt-level=3
+#![crate_type = "lib"]
+
+use std::sync::atomic::AtomicI32;
+use std::sync::atomic::Ordering::*;
+
+// CHECK-LABEL: @compare_exchange
+#[no_mangle]
+pub fn compare_exchange(a: &AtomicI32) {
+    // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 10 monotonic monotonic
+    // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 11 monotonic acquire
+    // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 12 monotonic seq_cst
+    let _ = a.compare_exchange(0, 10, Relaxed, Relaxed);
+    let _ = a.compare_exchange(0, 11, Relaxed, Acquire);
+    let _ = a.compare_exchange(0, 12, Relaxed, SeqCst);
+
+    // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 20 release monotonic
+    // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 21 release acquire
+    // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 22 release seq_cst
+    let _ = a.compare_exchange(0, 20, Release, Relaxed);
+    let _ = a.compare_exchange(0, 21, Release, Acquire);
+    let _ = a.compare_exchange(0, 22, Release, SeqCst);
+
+    // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 30 acquire monotonic
+    // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 31 acquire acquire
+    // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 32 acquire seq_cst
+    let _ = a.compare_exchange(0, 30, Acquire, Relaxed);
+    let _ = a.compare_exchange(0, 31, Acquire, Acquire);
+    let _ = a.compare_exchange(0, 32, Acquire, SeqCst);
+
+    // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 40 acq_rel monotonic
+    // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 41 acq_rel acquire
+    // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 42 acq_rel seq_cst
+    let _ = a.compare_exchange(0, 40, AcqRel, Relaxed);
+    let _ = a.compare_exchange(0, 41, AcqRel, Acquire);
+    let _ = a.compare_exchange(0, 42, AcqRel, SeqCst);
+
+    // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 50 seq_cst monotonic
+    // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 51 seq_cst acquire
+    // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 52 seq_cst seq_cst
+    let _ = a.compare_exchange(0, 50, SeqCst, Relaxed);
+    let _ = a.compare_exchange(0, 51, SeqCst, Acquire);
+    let _ = a.compare_exchange(0, 52, SeqCst, SeqCst);
+}
+
+// CHECK-LABEL: @compare_exchange_weak
+#[no_mangle]
+pub fn compare_exchange_weak(w: &AtomicI32) {
+    // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 10 monotonic monotonic
+    // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 11 monotonic acquire
+    // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 12 monotonic seq_cst
+    let _ = w.compare_exchange_weak(1, 10, Relaxed, Relaxed);
+    let _ = w.compare_exchange_weak(1, 11, Relaxed, Acquire);
+    let _ = w.compare_exchange_weak(1, 12, Relaxed, SeqCst);
+
+    // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 20 release monotonic
+    // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 21 release acquire
+    // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 22 release seq_cst
+    let _ = w.compare_exchange_weak(1, 20, Release, Relaxed);
+    let _ = w.compare_exchange_weak(1, 21, Release, Acquire);
+    let _ = w.compare_exchange_weak(1, 22, Release, SeqCst);
+
+    // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 30 acquire monotonic
+    // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 31 acquire acquire
+    // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 32 acquire seq_cst
+    let _ = w.compare_exchange_weak(1, 30, Acquire, Relaxed);
+    let _ = w.compare_exchange_weak(1, 31, Acquire, Acquire);
+    let _ = w.compare_exchange_weak(1, 32, Acquire, SeqCst);
+
+    // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 40 acq_rel monotonic
+    // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 41 acq_rel acquire
+    // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 42 acq_rel seq_cst
+    let _ = w.compare_exchange_weak(1, 40, AcqRel, Relaxed);
+    let _ = w.compare_exchange_weak(1, 41, AcqRel, Acquire);
+    let _ = w.compare_exchange_weak(1, 42, AcqRel, SeqCst);
+
+    // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 50 seq_cst monotonic
+    // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 51 seq_cst acquire
+    // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 52 seq_cst seq_cst
+    let _ = w.compare_exchange_weak(1, 50, SeqCst, Relaxed);
+    let _ = w.compare_exchange_weak(1, 51, SeqCst, Acquire);
+    let _ = w.compare_exchange_weak(1, 52, SeqCst, SeqCst);
+}
diff --git a/tests/codegen-llvm/atomicptr.rs b/tests/codegen-llvm/atomicptr.rs
new file mode 100644
index 00000000000..4819af40ca2
--- /dev/null
+++ b/tests/codegen-llvm/atomicptr.rs
@@ -0,0 +1,36 @@
+// LLVM does not support some atomic RMW operations on pointers, so inside codegen we lower those
+// to integer atomics, surrounded by casts to and from integer type.
+// This test ensures that we do the round-trip correctly for AtomicPtr::fetch_byte_add, and also
+// ensures that we do not have such a round-trip for AtomicPtr::swap, because LLVM supports pointer
+// arguments to `atomicrmw xchg`.
+
+//@ compile-flags: -Copt-level=3 -Cno-prepopulate-passes
+#![crate_type = "lib"]
+#![feature(strict_provenance_atomic_ptr)]
+
+use std::ptr::without_provenance_mut;
+use std::sync::atomic::AtomicPtr;
+use std::sync::atomic::Ordering::Relaxed;
+
+// Portability hack so that we can say [[USIZE]] instead of i64/i32/i16 for usize.
+// CHECK: @helper([[USIZE:i[0-9]+]] noundef %_1)
+#[no_mangle]
+pub fn helper(_: usize) {}
+
+// CHECK-LABEL: @atomicptr_fetch_byte_add
+#[no_mangle]
+pub fn atomicptr_fetch_byte_add(a: &AtomicPtr<u8>, v: usize) -> *mut u8 {
+    // CHECK: %[[INTPTR:.*]] = ptrtoint ptr %{{.*}} to [[USIZE]]
+    // CHECK-NEXT: %[[RET:.*]] = atomicrmw add ptr %{{.*}}, [[USIZE]] %[[INTPTR]]
+    // CHECK-NEXT: inttoptr [[USIZE]] %[[RET]] to ptr
+    a.fetch_byte_add(v, Relaxed)
+}
+
+// CHECK-LABEL: @atomicptr_swap
+#[no_mangle]
+pub fn atomicptr_swap(a: &AtomicPtr<u8>, ptr: *mut u8) -> *mut u8 {
+    // CHECK-NOT: ptrtoint
+    // CHECK: atomicrmw xchg ptr %{{.*}}, ptr %{{.*}} monotonic
+    // CHECK-NOT: inttoptr
+    a.swap(ptr, Relaxed)
+}
diff --git a/tests/codegen-llvm/autodiff/batched.rs b/tests/codegen-llvm/autodiff/batched.rs
new file mode 100644
index 00000000000..d27aed50e6c
--- /dev/null
+++ b/tests/codegen-llvm/autodiff/batched.rs
@@ -0,0 +1,116 @@
+//@ compile-flags: -Zautodiff=Enable -C opt-level=3  -Clto=fat
+//@ no-prefer-dynamic
+//@ needs-enzyme
+//
+// In Enzyme, we test against a large range of LLVM versions (5+) and don't have overly many
+// breakages. One benefit is that we match the IR generated by Enzyme only after running it
+// through LLVM's O3 pipeline, which will remove most of the noise.
+// However, our integration test could also be affected by changes in how rustc lowers MIR into
+// LLVM-IR, which could cause additional noise and thus breakages. If that's the case, we should
+// reduce this test to only match the first lines and the ret instructions.
+
+#![feature(autodiff)]
+
+use std::autodiff::autodiff_forward;
+
+#[autodiff_forward(d_square3, Dual, DualOnly)]
+#[autodiff_forward(d_square2, 4, Dual, DualOnly)]
+#[autodiff_forward(d_square1, 4, Dual, Dual)]
+#[no_mangle]
+fn square(x: &f32) -> f32 {
+    x * x
+}
+
+// d_sqaure2
+// CHECK: define internal fastcc [4 x float] @fwddiffe4square(float %x.0.val, [4 x ptr] %"x'")
+// CHECK-NEXT: start:
+// CHECK-NEXT:   %0 = extractvalue [4 x ptr] %"x'", 0
+// CHECK-NEXT:   %"_2'ipl" = load float, ptr %0, align 4
+// CHECK-NEXT:   %1 = extractvalue [4 x ptr] %"x'", 1
+// CHECK-NEXT:   %"_2'ipl1" = load float, ptr %1, align 4
+// CHECK-NEXT:   %2 = extractvalue [4 x ptr] %"x'", 2
+// CHECK-NEXT:   %"_2'ipl2" = load float, ptr %2, align 4
+// CHECK-NEXT:   %3 = extractvalue [4 x ptr] %"x'", 3
+// CHECK-NEXT:   %"_2'ipl3" = load float, ptr %3, align 4
+// CHECK-NEXT:   %4 = insertelement <4 x float> poison, float %"_2'ipl", i64 0
+// CHECK-NEXT:   %5 = insertelement <4 x float> %4, float %"_2'ipl1", i64 1
+// CHECK-NEXT:   %6 = insertelement <4 x float> %5, float %"_2'ipl2", i64 2
+// CHECK-NEXT:   %7 = insertelement <4 x float> %6, float %"_2'ipl3", i64 3
+// CHECK-NEXT:   %8 = fadd fast <4 x float> %7, %7
+// CHECK-NEXT:   %9 = insertelement <4 x float> poison, float %x.0.val, i64 0
+// CHECK-NEXT:   %10 = shufflevector <4 x float> %9, <4 x float> poison, <4 x i32> zeroinitializer
+// CHECK-NEXT:   %11 = fmul fast <4 x float> %8, %10
+// CHECK-NEXT:   %12 = extractelement <4 x float> %11, i64 0
+// CHECK-NEXT:   %13 = insertvalue [4 x float] undef, float %12, 0
+// CHECK-NEXT:   %14 = extractelement <4 x float> %11, i64 1
+// CHECK-NEXT:   %15 = insertvalue [4 x float] %13, float %14, 1
+// CHECK-NEXT:   %16 = extractelement <4 x float> %11, i64 2
+// CHECK-NEXT:   %17 = insertvalue [4 x float] %15, float %16, 2
+// CHECK-NEXT:   %18 = extractelement <4 x float> %11, i64 3
+// CHECK-NEXT:   %19 = insertvalue [4 x float] %17, float %18, 3
+// CHECK-NEXT:   ret [4 x float] %19
+// CHECK-NEXT: }
+
+// d_square3, the extra float is the original return value (x * x)
+// CHECK: define internal fastcc { float, [4 x float] } @fwddiffe4square.1(float %x.0.val, [4 x ptr] %"x'")
+// CHECK-NEXT: start:
+// CHECK-NEXT:   %0 = extractvalue [4 x ptr] %"x'", 0
+// CHECK-NEXT:   %"_2'ipl" = load float, ptr %0, align 4
+// CHECK-NEXT:   %1 = extractvalue [4 x ptr] %"x'", 1
+// CHECK-NEXT:   %"_2'ipl1" = load float, ptr %1, align 4
+// CHECK-NEXT:   %2 = extractvalue [4 x ptr] %"x'", 2
+// CHECK-NEXT:   %"_2'ipl2" = load float, ptr %2, align 4
+// CHECK-NEXT:   %3 = extractvalue [4 x ptr] %"x'", 3
+// CHECK-NEXT:   %"_2'ipl3" = load float, ptr %3, align 4
+// CHECK-NEXT:   %_0 = fmul float %x.0.val, %x.0.val
+// CHECK-NEXT:   %4 = insertelement <4 x float> poison, float %"_2'ipl", i64 0
+// CHECK-NEXT:   %5 = insertelement <4 x float> %4, float %"_2'ipl1", i64 1
+// CHECK-NEXT:   %6 = insertelement <4 x float> %5, float %"_2'ipl2", i64 2
+// CHECK-NEXT:   %7 = insertelement <4 x float> %6, float %"_2'ipl3", i64 3
+// CHECK-NEXT:   %8 = fadd fast <4 x float> %7, %7
+// CHECK-NEXT:   %9 = insertelement <4 x float> poison, float %x.0.val, i64 0
+// CHECK-NEXT:   %10 = shufflevector <4 x float> %9, <4 x float> poison, <4 x i32> zeroinitializer
+// CHECK-NEXT:   %11 = fmul fast <4 x float> %8, %10
+// CHECK-NEXT:   %12 = extractelement <4 x float> %11, i64 0
+// CHECK-NEXT:   %13 = insertvalue [4 x float] undef, float %12, 0
+// CHECK-NEXT:   %14 = extractelement <4 x float> %11, i64 1
+// CHECK-NEXT:   %15 = insertvalue [4 x float] %13, float %14, 1
+// CHECK-NEXT:   %16 = extractelement <4 x float> %11, i64 2
+// CHECK-NEXT:   %17 = insertvalue [4 x float] %15, float %16, 2
+// CHECK-NEXT:   %18 = extractelement <4 x float> %11, i64 3
+// CHECK-NEXT:   %19 = insertvalue [4 x float] %17, float %18, 3
+// CHECK-NEXT:   %20 = insertvalue { float, [4 x float] } undef, float %_0, 0
+// CHECK-NEXT:   %21 = insertvalue { float, [4 x float] } %20, [4 x float] %19, 1
+// CHECK-NEXT:   ret { float, [4 x float] } %21
+// CHECK-NEXT: }
+
+fn main() {
+    let x = std::hint::black_box(3.0);
+    let output = square(&x);
+    dbg!(&output);
+    assert_eq!(9.0, output);
+    dbg!(square(&x));
+
+    let mut df_dx1 = 1.0;
+    let mut df_dx2 = 2.0;
+    let mut df_dx3 = 3.0;
+    let mut df_dx4 = 0.0;
+    let [o1, o2, o3, o4] = d_square2(&x, &mut df_dx1, &mut df_dx2, &mut df_dx3, &mut df_dx4);
+    dbg!(o1, o2, o3, o4);
+    let [output2, o1, o2, o3, o4] =
+        d_square1(&x, &mut df_dx1, &mut df_dx2, &mut df_dx3, &mut df_dx4);
+    dbg!(o1, o2, o3, o4);
+    assert_eq!(output, output2);
+    assert!((6.0 - o1).abs() < 1e-10);
+    assert!((12.0 - o2).abs() < 1e-10);
+    assert!((18.0 - o3).abs() < 1e-10);
+    assert!((0.0 - o4).abs() < 1e-10);
+    assert_eq!(1.0, df_dx1);
+    assert_eq!(2.0, df_dx2);
+    assert_eq!(3.0, df_dx3);
+    assert_eq!(0.0, df_dx4);
+    assert_eq!(d_square3(&x, &mut df_dx1), 2.0 * o1);
+    assert_eq!(d_square3(&x, &mut df_dx2), 2.0 * o2);
+    assert_eq!(d_square3(&x, &mut df_dx3), 2.0 * o3);
+    assert_eq!(d_square3(&x, &mut df_dx4), 2.0 * o4);
+}
diff --git a/tests/codegen-llvm/autodiff/generic.rs b/tests/codegen-llvm/autodiff/generic.rs
new file mode 100644
index 00000000000..2f674079be0
--- /dev/null
+++ b/tests/codegen-llvm/autodiff/generic.rs
@@ -0,0 +1,42 @@
+//@ compile-flags: -Zautodiff=Enable -Zautodiff=NoPostopt -C opt-level=3 -Clto=fat
+//@ no-prefer-dynamic
+//@ needs-enzyme
+#![feature(autodiff)]
+
+use std::autodiff::autodiff_reverse;
+
+#[autodiff_reverse(d_square, Duplicated, Active)]
+fn square<T: std::ops::Mul<Output = T> + Copy>(x: &T) -> T {
+    *x * *x
+}
+
+// Ensure that `d_square::<f64>` code is generated even if `square::<f64>` was never called
+//
+// CHECK: ; generic::square
+// CHECK-NEXT: ; Function Attrs:
+// CHECK-NEXT: define internal {{.*}} double
+// CHECK-NEXT: start:
+// CHECK-NOT: ret
+// CHECK: fmul double
+
+// Ensure that `d_square::<f32>` code is generated
+//
+// CHECK: ; generic::square
+// CHECK-NEXT: ; Function Attrs: {{.*}}
+// CHECK-NEXT: define internal {{.*}} float
+// CHECK-NEXT: start:
+// CHECK-NOT: ret
+// CHECK: fmul float
+
+fn main() {
+    let xf32: f32 = std::hint::black_box(3.0);
+    let xf64: f64 = std::hint::black_box(3.0);
+
+    let outputf32 = square::<f32>(&xf32);
+    assert_eq!(9.0, outputf32);
+
+    let mut df_dxf64: f64 = std::hint::black_box(0.0);
+
+    let output_f64 = d_square::<f64>(&xf64, &mut df_dxf64, 1.0);
+    assert_eq!(6.0, df_dxf64);
+}
diff --git a/tests/codegen-llvm/autodiff/identical_fnc.rs b/tests/codegen-llvm/autodiff/identical_fnc.rs
new file mode 100644
index 00000000000..1c25b3d09ab
--- /dev/null
+++ b/tests/codegen-llvm/autodiff/identical_fnc.rs
@@ -0,0 +1,45 @@
+//@ compile-flags: -Zautodiff=Enable -C opt-level=3  -Clto=fat
+//@ no-prefer-dynamic
+//@ needs-enzyme
+//
+// Each autodiff invocation creates a new placeholder function, which we will replace on llvm-ir
+// level. If a user tries to differentiate two identical functions within the same compilation unit,
+// then LLVM might merge them in release mode before AD. In that case we can't rewrite one of the
+// merged placeholder function anymore, and compilation would fail. We prevent this by disabling
+// LLVM's merge_function pass before AD. Here we implicetely test that our solution keeps working.
+// We also explicetly test that we keep running merge_function after AD, by checking for two
+// identical function calls in the LLVM-IR, while having two different calls in the Rust code.
+#![feature(autodiff)]
+
+use std::autodiff::autodiff_reverse;
+
+#[autodiff_reverse(d_square, Duplicated, Active)]
+fn square(x: &f64) -> f64 {
+    x * x
+}
+
+#[autodiff_reverse(d_square2, Duplicated, Active)]
+fn square2(x: &f64) -> f64 {
+    x * x
+}
+
+// CHECK:; identical_fnc::main
+// CHECK-NEXT:; Function Attrs:
+// CHECK-NEXT:define internal void @_ZN13identical_fnc4main17hf4dbc69c8d2f9130E()
+// CHECK-NEXT:start:
+// CHECK-NOT:br
+// CHECK-NOT:ret
+// CHECK:; call identical_fnc::d_square
+// CHECK-NEXT:  call fastcc void @_ZN13identical_fnc8d_square17h4c364207a2f8e06dE(double %x.val, ptr noalias noundef nonnull align 8 dereferenceable(8) %dx1)
+// CHECK-NEXT:; call identical_fnc::d_square
+// CHECK-NEXT:  call fastcc void @_ZN13identical_fnc8d_square17h4c364207a2f8e06dE(double %x.val, ptr noalias noundef nonnull align 8 dereferenceable(8) %dx2)
+
+fn main() {
+    let x = std::hint::black_box(3.0);
+    let mut dx1 = std::hint::black_box(1.0);
+    let mut dx2 = std::hint::black_box(1.0);
+    let _ = d_square(&x, &mut dx1, 1.0);
+    let _ = d_square2(&x, &mut dx2, 1.0);
+    assert_eq!(dx1, 6.0);
+    assert_eq!(dx2, 6.0);
+}
diff --git a/tests/codegen-llvm/autodiff/inline.rs b/tests/codegen-llvm/autodiff/inline.rs
new file mode 100644
index 00000000000..65bed170207
--- /dev/null
+++ b/tests/codegen-llvm/autodiff/inline.rs
@@ -0,0 +1,23 @@
+//@ compile-flags: -Zautodiff=Enable -C opt-level=3  -Clto=fat -Zautodiff=NoPostopt
+//@ no-prefer-dynamic
+//@ needs-enzyme
+
+#![feature(autodiff)]
+
+use std::autodiff::autodiff_reverse;
+
+#[autodiff_reverse(d_square, Duplicated, Active)]
+fn square(x: &f64) -> f64 {
+    x * x
+}
+
+// CHECK: ; inline::d_square
+// CHECK-NEXT: ; Function Attrs: alwaysinline
+// CHECK-NOT: noinline
+// CHECK-NEXT: define internal fastcc void @_ZN6inline8d_square17h021c74e92c259cdeE
+fn main() {
+    let x = std::hint::black_box(3.0);
+    let mut dx1 = std::hint::black_box(1.0);
+    let _ = d_square(&x, &mut dx1, 1.0);
+    assert_eq!(dx1, 6.0);
+}
diff --git a/tests/codegen-llvm/autodiff/scalar.rs b/tests/codegen-llvm/autodiff/scalar.rs
new file mode 100644
index 00000000000..096b4209e84
--- /dev/null
+++ b/tests/codegen-llvm/autodiff/scalar.rs
@@ -0,0 +1,33 @@
+//@ compile-flags: -Zautodiff=Enable -C opt-level=3  -Clto=fat
+//@ no-prefer-dynamic
+//@ needs-enzyme
+#![feature(autodiff)]
+
+use std::autodiff::autodiff_reverse;
+
+#[autodiff_reverse(d_square, Duplicated, Active)]
+#[no_mangle]
+fn square(x: &f64) -> f64 {
+    x * x
+}
+
+// CHECK:define internal fastcc double @diffesquare(double %x.0.val, ptr nocapture nonnull align 8 %"x'"
+// CHECK-NEXT:invertstart:
+// CHECK-NEXT:  %_0 = fmul double %x.0.val, %x.0.val
+// CHECK-NEXT:  %0 = fadd fast double %x.0.val, %x.0.val
+// CHECK-NEXT:  %1 = load double, ptr %"x'", align 8
+// CHECK-NEXT:  %2 = fadd fast double %1, %0
+// CHECK-NEXT:  store double %2, ptr %"x'", align 8
+// CHECK-NEXT:  ret double %_0
+// CHECK-NEXT:}
+
+fn main() {
+    let x = std::hint::black_box(3.0);
+    let output = square(&x);
+    assert_eq!(9.0, output);
+
+    let mut df_dx = 0.0;
+    let output_ = d_square(&x, &mut df_dx, 1.0);
+    assert_eq!(output, output_);
+    assert_eq!(6.0, df_dx);
+}
diff --git a/tests/codegen-llvm/autodiff/sret.rs b/tests/codegen-llvm/autodiff/sret.rs
new file mode 100644
index 00000000000..d2fa85e3e37
--- /dev/null
+++ b/tests/codegen-llvm/autodiff/sret.rs
@@ -0,0 +1,45 @@
+//@ compile-flags: -Zautodiff=Enable -C opt-level=3  -Clto=fat
+//@ no-prefer-dynamic
+//@ needs-enzyme
+
+// This test is almost identical to the scalar.rs one,
+// but we intentionally add a few more floats.
+// `df` would ret `{ f64, f32, f32 }`, but is lowered as an sret.
+// We therefore use this test to verify some of our sret handling.
+
+#![feature(autodiff)]
+
+use std::autodiff::autodiff_reverse;
+
+#[no_mangle]
+#[autodiff_reverse(df, Active, Active, Active)]
+fn primal(x: f32, y: f32) -> f64 {
+    (x * x * y) as f64
+}
+
+// CHECK:define internal fastcc void @_ZN4sret2df17h93be4316dd8ea006E(ptr dead_on_unwind noalias nocapture noundef nonnull writable writeonly align 8 dereferenceable(16) initializes((0, 16)) %_0, float noundef %x, float noundef %y)
+// CHECK-NEXT:start:
+// CHECK-NEXT:  %0 = tail call fastcc { double, float, float } @diffeprimal(float %x, float %y)
+// CHECK-NEXT:  %.elt = extractvalue { double, float, float } %0, 0
+// CHECK-NEXT:  store double %.elt, ptr %_0, align 8
+// CHECK-NEXT:  %_0.repack1 = getelementptr inbounds nuw i8, ptr %_0, i64 8
+// CHECK-NEXT:  %.elt2 = extractvalue { double, float, float } %0, 1
+// CHECK-NEXT:  store float %.elt2, ptr %_0.repack1, align 8
+// CHECK-NEXT:  %_0.repack3 = getelementptr inbounds nuw i8, ptr %_0, i64 12
+// CHECK-NEXT:  %.elt4 = extractvalue { double, float, float } %0, 2
+// CHECK-NEXT:  store float %.elt4, ptr %_0.repack3, align 4
+// CHECK-NEXT:  ret void
+// CHECK-NEXT:}
+
+fn main() {
+    let x = std::hint::black_box(3.0);
+    let y = std::hint::black_box(2.5);
+    let scalar = std::hint::black_box(1.0);
+    let (r1, r2, r3) = df(x, y, scalar);
+    // 3*3*1.5 = 22.5
+    assert_eq!(r1, 22.5);
+    // 2*x*y = 2*3*2.5 = 15.0
+    assert_eq!(r2, 15.0);
+    // x*x*1 = 3*3 = 9
+    assert_eq!(r3, 9.0);
+}
diff --git a/tests/codegen-llvm/autodiffv2.rs b/tests/codegen-llvm/autodiffv2.rs
new file mode 100644
index 00000000000..a40d19d3be3
--- /dev/null
+++ b/tests/codegen-llvm/autodiffv2.rs
@@ -0,0 +1,113 @@
+//@ compile-flags: -Zautodiff=Enable -C opt-level=3  -Clto=fat
+//@ no-prefer-dynamic
+//@ needs-enzyme
+//
+// In Enzyme, we test against a large range of LLVM versions (5+) and don't have overly many
+// breakages. One benefit is that we match the IR generated by Enzyme only after running it
+// through LLVM's O3 pipeline, which will remove most of the noise.
+// However, our integration test could also be affected by changes in how rustc lowers MIR into
+// LLVM-IR, which could cause additional noise and thus breakages. If that's the case, we should
+// reduce this test to only match the first lines and the ret instructions.
+//
+// The function tested here has 4 inputs and 5 outputs, so we could either call forward-mode
+// autodiff 4 times, or reverse mode 5 times. Since a forward-mode call is usually faster than
+// reverse mode, we prefer it here. This file also tests a new optimization (batch mode), which
+// allows us to call forward-mode autodiff only once, and get all 5 outputs in a single call.
+//
+// We support 2 different batch modes. `d_square2` has the same interface as scalar forward-mode,
+// but each shadow argument is `width` times larger (thus 16 and 20 elements here).
+// `d_square3` instead takes `width` (4) shadow arguments, which are all the same size as the
+// original function arguments.
+//
+// FIXME(autodiff): We currently can't test `d_square1` and `d_square3` in the same file, since they
+// generate the same dummy functions which get merged by LLVM, breaking pieces of our pipeline which
+// try to rewrite the dummy functions later. We should consider to change to pure declarations both
+// in our frontend and in the llvm backend to avoid these issues.
+
+#![feature(autodiff)]
+
+use std::autodiff::autodiff;
+
+#[no_mangle]
+//#[autodiff(d_square1, Forward, Dual, Dual)]
+#[autodiff(d_square2, Forward, 4, Dualv, Dualv)]
+#[autodiff(d_square3, Forward, 4, Dual, Dual)]
+fn square(x: &[f32], y: &mut [f32]) {
+    assert!(x.len() >= 4);
+    assert!(y.len() >= 5);
+    y[0] = 4.3 * x[0] + 1.2 * x[1] + 3.4 * x[2] + 2.1 * x[3];
+    y[1] = 2.3 * x[0] + 4.5 * x[1] + 1.7 * x[2] + 6.4 * x[3];
+    y[2] = 1.1 * x[0] + 3.3 * x[1] + 2.5 * x[2] + 4.7 * x[3];
+    y[3] = 5.2 * x[0] + 1.4 * x[1] + 2.6 * x[2] + 3.8 * x[3];
+    y[4] = 1.0 * x[0] + 2.0 * x[1] + 3.0 * x[2] + 4.0 * x[3];
+}
+
+fn main() {
+    let x1 = std::hint::black_box(vec![0.0, 1.0, 2.0, 3.0]);
+
+    let dx1 = std::hint::black_box(vec![1.0; 12]);
+
+    let z1 = std::hint::black_box(vec![1.0, 0.0, 0.0, 0.0]);
+    let z2 = std::hint::black_box(vec![0.0, 1.0, 0.0, 0.0]);
+    let z3 = std::hint::black_box(vec![0.0, 0.0, 1.0, 0.0]);
+    let z4 = std::hint::black_box(vec![0.0, 0.0, 0.0, 1.0]);
+
+    let z5 = std::hint::black_box(vec![
+        1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0,
+    ]);
+
+    let mut y1 = std::hint::black_box(vec![0.0; 5]);
+    let mut y2 = std::hint::black_box(vec![0.0; 5]);
+    let mut y3 = std::hint::black_box(vec![0.0; 5]);
+    let mut y4 = std::hint::black_box(vec![0.0; 5]);
+
+    let mut y5 = std::hint::black_box(vec![0.0; 5]);
+
+    let mut y6 = std::hint::black_box(vec![0.0; 5]);
+
+    let mut dy1_1 = std::hint::black_box(vec![0.0; 5]);
+    let mut dy1_2 = std::hint::black_box(vec![0.0; 5]);
+    let mut dy1_3 = std::hint::black_box(vec![0.0; 5]);
+    let mut dy1_4 = std::hint::black_box(vec![0.0; 5]);
+
+    let mut dy2 = std::hint::black_box(vec![0.0; 20]);
+
+    let mut dy3_1 = std::hint::black_box(vec![0.0; 5]);
+    let mut dy3_2 = std::hint::black_box(vec![0.0; 5]);
+    let mut dy3_3 = std::hint::black_box(vec![0.0; 5]);
+    let mut dy3_4 = std::hint::black_box(vec![0.0; 5]);
+
+    // scalar.
+    //d_square1(&x1, &z1, &mut y1, &mut dy1_1);
+    //d_square1(&x1, &z2, &mut y2, &mut dy1_2);
+    //d_square1(&x1, &z3, &mut y3, &mut dy1_3);
+    //d_square1(&x1, &z4, &mut y4, &mut dy1_4);
+
+    // assert y1 == y2 == y3 == y4
+    //for i in 0..5 {
+    //    assert_eq!(y1[i], y2[i]);
+    //    assert_eq!(y1[i], y3[i]);
+    //    assert_eq!(y1[i], y4[i]);
+    //}
+
+    // batch mode A)
+    d_square2(&x1, &z5, &mut y5, &mut dy2);
+
+    // assert y1 == y2 == y3 == y4 == y5
+    //for i in 0..5 {
+    //    assert_eq!(y1[i], y5[i]);
+    //}
+
+    // batch mode B)
+    d_square3(&x1, &z1, &z2, &z3, &z4, &mut y6, &mut dy3_1, &mut dy3_2, &mut dy3_3, &mut dy3_4);
+    for i in 0..5 {
+        assert_eq!(y5[i], y6[i]);
+    }
+
+    for i in 0..5 {
+        assert_eq!(dy2[0..5][i], dy3_1[i]);
+        assert_eq!(dy2[5..10][i], dy3_2[i]);
+        assert_eq!(dy2[10..15][i], dy3_3[i]);
+        assert_eq!(dy2[15..20][i], dy3_4[i]);
+    }
+}
diff --git a/tests/codegen-llvm/autovec/dont-shuffle-bswaps-opt2.rs b/tests/codegen-llvm/autovec/dont-shuffle-bswaps-opt2.rs
new file mode 100644
index 00000000000..c354228acc5
--- /dev/null
+++ b/tests/codegen-llvm/autovec/dont-shuffle-bswaps-opt2.rs
@@ -0,0 +1,31 @@
+//@ compile-flags: -Copt-level=2
+
+#![crate_type = "lib"]
+#![no_std]
+
+// This test is paired with the arch-specific -opt3.rs test.
+
+// The code is from https://github.com/rust-lang/rust/issues/122805.
+// Ensure we do not generate the shufflevector instruction
+// to avoid complicating the code.
+
+// CHECK-LABEL: define{{.*}}void @convert(
+// CHECK-NOT: shufflevector
+#[no_mangle]
+pub fn convert(value: [u16; 8]) -> [u8; 16] {
+    #[cfg(target_endian = "little")]
+    let bswap = u16::to_be;
+    #[cfg(target_endian = "big")]
+    let bswap = u16::to_le;
+    let addr16 = [
+        bswap(value[0]),
+        bswap(value[1]),
+        bswap(value[2]),
+        bswap(value[3]),
+        bswap(value[4]),
+        bswap(value[5]),
+        bswap(value[6]),
+        bswap(value[7]),
+    ];
+    unsafe { core::mem::transmute::<_, [u8; 16]>(addr16) }
+}
diff --git a/tests/codegen-llvm/autovec/dont-shuffle-bswaps-opt3.rs b/tests/codegen-llvm/autovec/dont-shuffle-bswaps-opt3.rs
new file mode 100644
index 00000000000..203d12005de
--- /dev/null
+++ b/tests/codegen-llvm/autovec/dont-shuffle-bswaps-opt3.rs
@@ -0,0 +1,42 @@
+//@ revisions: AARCH64 X86_64 Z13
+//@ compile-flags: -Copt-level=3
+//@[AARCH64] only-aarch64
+//@[X86_64] only-x86_64
+//@[Z13] only-s390x
+//@[Z13] compile-flags: -Ctarget-cpu=z13
+
+#![crate_type = "lib"]
+#![no_std]
+
+// This test is paired with the arch-neutral -opt2.rs test
+
+// The code is from https://github.com/rust-lang/rust/issues/122805.
+// Ensure we do not generate the shufflevector instruction
+// to avoid complicating the code.
+
+// CHECK-LABEL: define{{.*}}void @convert(
+// CHECK-NOT: shufflevector
+
+// On higher opt levels, this should just be a bswap:
+// CHECK: load <8 x i16>
+// CHECK-NEXT: call <8 x i16> @llvm.bswap
+// CHECK-NEXT: store <8 x i16>
+// CHECK-NEXT: ret void
+#[no_mangle]
+pub fn convert(value: [u16; 8]) -> [u8; 16] {
+    #[cfg(target_endian = "little")]
+    let bswap = u16::to_be;
+    #[cfg(target_endian = "big")]
+    let bswap = u16::to_le;
+    let addr16 = [
+        bswap(value[0]),
+        bswap(value[1]),
+        bswap(value[2]),
+        bswap(value[3]),
+        bswap(value[4]),
+        bswap(value[5]),
+        bswap(value[6]),
+        bswap(value[7]),
+    ];
+    unsafe { core::mem::transmute::<_, [u8; 16]>(addr16) }
+}
diff --git a/tests/codegen-llvm/autovectorize-f32x4.rs b/tests/codegen-llvm/autovectorize-f32x4.rs
new file mode 100644
index 00000000000..254362842f9
--- /dev/null
+++ b/tests/codegen-llvm/autovectorize-f32x4.rs
@@ -0,0 +1,37 @@
+//@ compile-flags: -C opt-level=3 -Z merge-functions=disabled
+//@ only-x86_64
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @auto_vectorize_direct
+#[no_mangle]
+pub fn auto_vectorize_direct(a: [f32; 4], b: [f32; 4]) -> [f32; 4] {
+    // CHECK: load <4 x float>
+    // CHECK: load <4 x float>
+    // CHECK: fadd <4 x float>
+    // CHECK: store <4 x float>
+    [a[0] + b[0], a[1] + b[1], a[2] + b[2], a[3] + b[3]]
+}
+
+// CHECK-LABEL: @auto_vectorize_loop
+#[no_mangle]
+pub fn auto_vectorize_loop(a: [f32; 4], b: [f32; 4]) -> [f32; 4] {
+    // CHECK: load <4 x float>
+    // CHECK: load <4 x float>
+    // CHECK: fadd <4 x float>
+    // CHECK: store <4 x float>
+    let mut c = [0.0; 4];
+    for i in 0..4 {
+        c[i] = a[i] + b[i];
+    }
+    c
+}
+
+// CHECK-LABEL: @auto_vectorize_array_from_fn
+#[no_mangle]
+pub fn auto_vectorize_array_from_fn(a: [f32; 4], b: [f32; 4]) -> [f32; 4] {
+    // CHECK: load <4 x float>
+    // CHECK: load <4 x float>
+    // CHECK: fadd <4 x float>
+    // CHECK: store <4 x float>
+    std::array::from_fn(|i| a[i] + b[i])
+}
diff --git a/tests/codegen-llvm/auxiliary/extern_decl.rs b/tests/codegen-llvm/auxiliary/extern_decl.rs
new file mode 100644
index 00000000000..d17e77b1444
--- /dev/null
+++ b/tests/codegen-llvm/auxiliary/extern_decl.rs
@@ -0,0 +1,13 @@
+// Auxiliary crate that exports a function and static. Both always
+// evaluate to `71`. We force mutability on the static to prevent
+// it from being inlined as constant.
+
+#![crate_type = "lib"]
+
+#[no_mangle]
+pub fn extern_fn() -> u8 {
+    unsafe { extern_static }
+}
+
+#[no_mangle]
+pub static mut extern_static: u8 = 71;
diff --git a/tests/codegen-llvm/auxiliary/nounwind.rs b/tests/codegen-llvm/auxiliary/nounwind.rs
new file mode 100644
index 00000000000..40f66442c6e
--- /dev/null
+++ b/tests/codegen-llvm/auxiliary/nounwind.rs
@@ -0,0 +1,2 @@
+#[no_mangle]
+pub fn bar() {}
diff --git a/tests/codegen-llvm/auxiliary/thread_local_aux.rs b/tests/codegen-llvm/auxiliary/thread_local_aux.rs
new file mode 100644
index 00000000000..bebaa7754dd
--- /dev/null
+++ b/tests/codegen-llvm/auxiliary/thread_local_aux.rs
@@ -0,0 +1,5 @@
+#![crate_type = "lib"]
+
+use std::cell::Cell;
+
+thread_local!(pub static A: Cell<u64> = const { Cell::new(0) });
diff --git a/tests/codegen-llvm/avr/avr-func-addrspace.rs b/tests/codegen-llvm/avr/avr-func-addrspace.rs
new file mode 100644
index 00000000000..e0192f8b45a
--- /dev/null
+++ b/tests/codegen-llvm/avr/avr-func-addrspace.rs
@@ -0,0 +1,106 @@
+//@ add-core-stubs
+//@ compile-flags: -Copt-level=3 --target=avr-none -C target-cpu=atmega328p --crate-type=rlib -C panic=abort
+//@ needs-llvm-components: avr
+
+// This test validates that function pointers can be stored in global variables
+// and called upon. It ensures that Rust emits function pointers in the correct
+// address space to LLVM so that an assertion error relating to casting is
+// not triggered.
+//
+// It also validates that functions can be called through function pointers
+// through traits.
+
+#![feature(no_core, lang_items, intrinsics, unboxed_closures, arbitrary_self_types)]
+#![crate_type = "lib"]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+#[rustc_intrinsic]
+pub unsafe fn transmute<Src, Dst>(src: Src) -> Dst;
+
+pub static mut STORAGE_FOO: fn(&usize, &mut u32) -> Result<(), ()> = arbitrary_black_box;
+pub static mut STORAGE_BAR: u32 = 12;
+
+fn arbitrary_black_box(ptr: &usize, _: &mut u32) -> Result<(), ()> {
+    let raw_ptr = ptr as *const usize;
+    let _v: usize = unsafe { *raw_ptr };
+    loop {}
+}
+
+#[inline(never)]
+#[no_mangle]
+fn call_through_fn_trait(a: &mut impl Fn<(), Output = ()>) {
+    (*a)()
+}
+
+#[inline(never)]
+fn update_bar_value() {
+    unsafe {
+        STORAGE_BAR = 88;
+    }
+}
+
+// CHECK: define dso_local void @test(){{.+}}addrspace(1)
+#[no_mangle]
+pub extern "C" fn test() {
+    let mut buf = 7;
+
+    // A call through the Fn trait must use address space 1.
+    //
+    // CHECK: call{{.+}}addrspace(1) void @call_through_fn_trait({{.*}})
+    call_through_fn_trait(&mut update_bar_value);
+
+    // A call through a global variable must use address space 1.
+    // CHECK: load {{.*}}addrspace(1){{.+}}FOO
+    unsafe {
+        STORAGE_FOO(&1, &mut buf);
+    }
+}
+
+// Validate that we can codegen transmutes between data ptrs and fn ptrs.
+
+// CHECK: define{{.+}}ptr addrspace(1) @transmute_data_ptr_to_fn(ptr{{.*}} %x)
+#[no_mangle]
+pub unsafe fn transmute_data_ptr_to_fn(x: *const ()) -> fn() {
+    // It doesn't matter precisely how this is codegenned (through memory or an addrspacecast),
+    // as long as it doesn't cause a verifier error by using `bitcast`.
+    transmute(x)
+}
+
+// CHECK: define{{.+}}ptr @transmute_fn_ptr_to_data(ptr addrspace(1){{.*}} %x)
+#[no_mangle]
+pub unsafe fn transmute_fn_ptr_to_data(x: fn()) -> *const () {
+    // It doesn't matter precisely how this is codegenned (through memory or an addrspacecast),
+    // as long as it doesn't cause a verifier error by using `bitcast`.
+    transmute(x)
+}
+
+pub enum Either<T, U> {
+    A(T),
+    B(U),
+}
+
+// Previously, we would codegen this as passing/returning a scalar pair of `{ i8, ptr }`,
+// with the `ptr` field representing both `&i32` and `fn()` depending on the variant.
+// This is incorrect, because `fn()` should be `ptr addrspace(1)`, not `ptr`.
+
+// CHECK: define{{.+}}void @should_not_combine_addrspace(ptr{{.+}}sret{{.+}}%_0, ptr{{.+}}%x)
+#[no_mangle]
+#[inline(never)]
+pub fn should_not_combine_addrspace(x: Either<&i32, fn()>) -> Either<&i32, fn()> {
+    x
+}
+
+// The incorrectness described above would result in us producing (after optimizations)
+// a `ptrtoint`/`inttoptr` roundtrip to convert from `ptr` to `ptr addrspace(1)`.
+
+// CHECK-LABEL: @call_with_fn_ptr
+#[no_mangle]
+pub fn call_with_fn_ptr<'a>(f: fn()) -> Either<&'a i32, fn()> {
+    // CHECK-NOT: ptrtoint
+    // CHECK-NOT: inttoptr
+    // CHECK: call addrspace(1) void @should_not_combine_addrspace
+    should_not_combine_addrspace(Either::B(f))
+}
diff --git a/tests/codegen-llvm/bigint-helpers.rs b/tests/codegen-llvm/bigint-helpers.rs
new file mode 100644
index 00000000000..355cccb8150
--- /dev/null
+++ b/tests/codegen-llvm/bigint-helpers.rs
@@ -0,0 +1,13 @@
+//@ compile-flags: -C opt-level=3
+
+#![crate_type = "lib"]
+#![feature(bigint_helper_methods)]
+
+// CHECK-LABEL: @u32_carrying_add
+#[no_mangle]
+pub fn u32_carrying_add(a: u32, b: u32, c: bool) -> (u32, bool) {
+    // CHECK: @llvm.uadd.with.overflow.i32
+    // CHECK: @llvm.uadd.with.overflow.i32
+    // CHECK: or disjoint i1
+    u32::carrying_add(a, b, c)
+}
diff --git a/tests/codegen-llvm/binary-heap-peek-mut-pop-no-panic.rs b/tests/codegen-llvm/binary-heap-peek-mut-pop-no-panic.rs
new file mode 100644
index 00000000000..2c40327f624
--- /dev/null
+++ b/tests/codegen-llvm/binary-heap-peek-mut-pop-no-panic.rs
@@ -0,0 +1,13 @@
+//@ compile-flags: -Copt-level=3
+//@ ignore-std-debug-assertions
+#![crate_type = "lib"]
+
+use std::collections::binary_heap::PeekMut;
+
+// CHECK-LABEL: @peek_mut_pop
+#[no_mangle]
+pub fn peek_mut_pop(peek_mut: PeekMut<u32>) -> u32 {
+    // CHECK-NOT: panic
+    // CHECK-NOT: unwrap_failed
+    PeekMut::pop(peek_mut)
+}
diff --git a/tests/codegen-llvm/binary-search-index-no-bound-check.rs b/tests/codegen-llvm/binary-search-index-no-bound-check.rs
new file mode 100644
index 00000000000..d59c0beec64
--- /dev/null
+++ b/tests/codegen-llvm/binary-search-index-no-bound-check.rs
@@ -0,0 +1,35 @@
+//@ compile-flags: -Copt-level=3
+#![crate_type = "lib"]
+
+// Make sure no bounds checks are emitted when slicing or indexing
+// with an index from `binary_search`.
+
+// CHECK-LABEL: @binary_search_index_no_bounds_check
+#[no_mangle]
+pub fn binary_search_index_no_bounds_check(s: &[u8]) -> u8 {
+    // CHECK-NOT: panic
+    // CHECK-NOT: slice_start_index_len_fail
+    // CHECK-NOT: slice_end_index_len_fail
+    // CHECK-NOT: panic_bounds_check
+    if let Ok(idx) = s.binary_search(&b'\\') { s[idx] } else { 42 }
+}
+
+// Similarly, check that `partition_point` is known to return a valid fencepost.
+
+// CHECK-LABEL: @unknown_split
+#[no_mangle]
+pub fn unknown_split(x: &[i32], i: usize) -> (&[i32], &[i32]) {
+    // This just makes sure that the subsequent function is looking for the
+    // absence of something that might actually be there.
+
+    // CHECK: call core::panicking::panic
+    x.split_at(i)
+}
+
+// CHECK-LABEL: @partition_point_split_no_bounds_check
+#[no_mangle]
+pub fn partition_point_split_no_bounds_check(x: &[i32], needle: i32) -> (&[i32], &[i32]) {
+    // CHECK-NOT: call core::panicking::panic
+    let i = x.partition_point(|p| p < &needle);
+    x.split_at(i)
+}
diff --git a/tests/codegen-llvm/bool-cmp.rs b/tests/codegen-llvm/bool-cmp.rs
new file mode 100644
index 00000000000..71d3411689f
--- /dev/null
+++ b/tests/codegen-llvm/bool-cmp.rs
@@ -0,0 +1,18 @@
+// This is a test for optimal Ord trait implementation for bool.
+// See <https://github.com/rust-lang/rust/issues/66780> for more info.
+
+//@ compile-flags: -C opt-level=3
+
+#![crate_type = "lib"]
+
+use std::cmp::Ordering;
+
+// CHECK-LABEL: @cmp_bool
+#[no_mangle]
+pub fn cmp_bool(a: bool, b: bool) -> Ordering {
+    // LLVM 10 produces (zext a) + (sext b), but the final lowering is (zext a) - (zext b).
+    // CHECK: zext i1
+    // CHECK: {{z|s}}ext i1
+    // CHECK: {{sub|add}} nsw
+    a.cmp(&b)
+}
diff --git a/tests/codegen-llvm/bounds-checking/gep-issue-133979.rs b/tests/codegen-llvm/bounds-checking/gep-issue-133979.rs
new file mode 100644
index 00000000000..876bdbfb0e1
--- /dev/null
+++ b/tests/codegen-llvm/bounds-checking/gep-issue-133979.rs
@@ -0,0 +1,22 @@
+//! Issue: <https://github.com/rust-lang/rust/issues/133979>
+//! Check that bounds checking are eliminated.
+
+//@ compile-flags: -Copt-level=2
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @test(
+#[no_mangle]
+fn test(a: &[&[u8]]) -> u32 {
+    // CHECK-NOT: panic_bounds_check
+    a.iter()
+        .enumerate()
+        .map(|(y, b)| {
+            b.iter()
+                .enumerate()
+                .filter(|(_, c)| **c == b'A')
+                .map(|(x, _)| a[y][x] as u32)
+                .sum::<u32>()
+        })
+        .sum()
+}
diff --git a/tests/codegen-llvm/box-default-debug-copies.rs b/tests/codegen-llvm/box-default-debug-copies.rs
new file mode 100644
index 00000000000..06cc41b21c0
--- /dev/null
+++ b/tests/codegen-llvm/box-default-debug-copies.rs
@@ -0,0 +1,28 @@
+//@ compile-flags: -Copt-level=0
+
+// Test to make sure that `<Box<T>>::default` does not create too many copies of `T` on the stack.
+// in debug mode. This regressed in dd0620b86721ae8cae86736443acd3f72ba6fc32 to
+// four `T` allocas.
+//
+// See https://github.com/rust-lang/rust/issues/136043 for more context.
+//
+// FIXME: This test only wants to ensure that there are at most two allocas of `T` created, instead
+// of checking for exactly two.
+
+#![crate_type = "lib"]
+
+#[allow(dead_code)]
+pub struct Thing([u8; 1000000]);
+
+impl Default for Thing {
+    fn default() -> Self {
+        Thing([0; 1000000])
+    }
+}
+
+// CHECK-COUNT-2: %{{.*}} = alloca {{.*}}1000000
+// CHECK-NOT: %{{.*}} = alloca {{.*}}1000000
+#[no_mangle]
+pub fn box_default_single_copy() -> Box<Thing> {
+    Box::default()
+}
diff --git a/tests/codegen-llvm/box-uninit-bytes.rs b/tests/codegen-llvm/box-uninit-bytes.rs
new file mode 100644
index 00000000000..0cc01148595
--- /dev/null
+++ b/tests/codegen-llvm/box-uninit-bytes.rs
@@ -0,0 +1,46 @@
+//@ compile-flags: -Copt-level=3
+#![crate_type = "lib"]
+
+use std::mem::MaybeUninit;
+
+// Boxing a `MaybeUninit` value should not copy junk from the stack
+#[no_mangle]
+pub fn box_uninitialized() -> Box<MaybeUninit<usize>> {
+    // CHECK-LABEL: @box_uninitialized
+    // CHECK-NOT: store
+    // CHECK-NOT: alloca
+    // CHECK-NOT: memcpy
+    // CHECK-NOT: memset
+    Box::new(MaybeUninit::uninit())
+}
+
+// https://github.com/rust-lang/rust/issues/58201
+#[no_mangle]
+pub fn box_uninitialized2() -> Box<MaybeUninit<[usize; 1024 * 1024]>> {
+    // CHECK-LABEL: @box_uninitialized2
+    // CHECK-NOT: store
+    // CHECK-NOT: alloca
+    // CHECK-NOT: memcpy
+    // CHECK-NOT: memset
+    Box::new(MaybeUninit::uninit())
+}
+
+#[repr(align(1024))]
+pub struct LotsaPadding(usize);
+
+// Boxing a value with padding should not copy junk from the stack
+#[no_mangle]
+pub fn box_lotsa_padding() -> Box<LotsaPadding> {
+    // CHECK-LABEL: @box_lotsa_padding
+    // CHECK-NOT: alloca
+    // CHECK-NOT: getelementptr
+    // CHECK-NOT: memcpy
+    // CHECK-NOT: memset
+    Box::new(LotsaPadding(42))
+}
+
+// Hide the `allocalign` attribute in the declaration of __rust_alloc
+// from the CHECK-NOT above, and also verify the attributes got set reasonably.
+// CHECK: declare {{(dso_local )?}}noalias noundef ptr @{{.*}}__rust_alloc(i{{[0-9]+}} noundef, i{{[0-9]+}} allocalign noundef) unnamed_addr [[RUST_ALLOC_ATTRS:#[0-9]+]]
+
+// CHECK-DAG: attributes [[RUST_ALLOC_ATTRS]] = { {{.*}} allockind("alloc,uninitialized,aligned") allocsize(0) {{(uwtable )?}}"alloc-family"="__rust_alloc" {{.*}} }
diff --git a/tests/codegen-llvm/bpf-alu32.rs b/tests/codegen-llvm/bpf-alu32.rs
new file mode 100644
index 00000000000..5955bf3317f
--- /dev/null
+++ b/tests/codegen-llvm/bpf-alu32.rs
@@ -0,0 +1,11 @@
+//@ only-bpf
+#![crate_type = "lib"]
+#![feature(bpf_target_feature)]
+#![no_std]
+
+#[no_mangle]
+#[target_feature(enable = "alu32")]
+// CHECK: define i8 @foo(i8 returned %arg) unnamed_addr #0 {
+pub unsafe fn foo(arg: u8) -> u8 {
+    arg
+}
diff --git a/tests/codegen-llvm/branch-protection.rs b/tests/codegen-llvm/branch-protection.rs
new file mode 100644
index 00000000000..d67e494cc0d
--- /dev/null
+++ b/tests/codegen-llvm/branch-protection.rs
@@ -0,0 +1,94 @@
+// Test that the correct module flags are emitted with different branch protection flags.
+
+//@ add-core-stubs
+//@ revisions: BTI PACRET LEAF BKEY PAUTHLR PAUTHLR_BKEY PAUTHLR_LEAF PAUTHLR_BTI NONE
+//@ needs-llvm-components: aarch64
+//@ [BTI] compile-flags: -Z branch-protection=bti
+//@ [PACRET] compile-flags: -Z branch-protection=pac-ret
+//@ [LEAF] compile-flags: -Z branch-protection=pac-ret,leaf
+//@ [BKEY] compile-flags: -Z branch-protection=pac-ret,b-key
+//@ [PAUTHLR] compile-flags: -Z branch-protection=pac-ret,pc
+//@ [PAUTHLR_BKEY] compile-flags: -Z branch-protection=pac-ret,pc,b-key
+//@ [PAUTHLR_LEAF] compile-flags: -Z branch-protection=pac-ret,pc,leaf
+//@ [PAUTHLR_BTI] compile-flags: -Z branch-protection=bti,pac-ret,pc
+//@ compile-flags: --target aarch64-unknown-linux-gnu
+
+#![crate_type = "lib"]
+#![feature(no_core, lang_items)]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+// A basic test function.
+// CHECK: @test(){{.*}} [[ATTR:#[0-9]+]] {
+#[no_mangle]
+pub fn test() {}
+
+// BTI: attributes [[ATTR]] = {{.*}} "branch-target-enforcement"
+// BTI: !"branch-target-enforcement", i32 1
+// BTI: !"sign-return-address", i32 0
+// BTI: !"branch-protection-pauth-lr", i32 0
+// BTI: !"sign-return-address-all", i32 0
+// BTI: !"sign-return-address-with-bkey", i32 0
+
+// PACRET: attributes [[ATTR]] = {{.*}} "sign-return-address"="non-leaf"
+// PACRET-SAME: "sign-return-address-key"="a_key"
+// PACRET: !"branch-target-enforcement", i32 0
+// PACRET: !"sign-return-address", i32 1
+// PACRET: !"branch-protection-pauth-lr", i32 0
+// PACRET: !"sign-return-address-all", i32 0
+// PACRET: !"sign-return-address-with-bkey", i32 0
+
+// LEAF: attributes [[ATTR]] = {{.*}} "sign-return-address"="all"
+// LEAF-SAME: "sign-return-address-key"="a_key"
+// LEAF: !"branch-target-enforcement", i32 0
+// LEAF: !"sign-return-address", i32 1
+// LEAF: !"branch-protection-pauth-lr", i32 0
+// LEAF: !"sign-return-address-all", i32 1
+// LEAF: !"sign-return-address-with-bkey", i32 0
+
+// BKEY: attributes [[ATTR]] = {{.*}} "sign-return-address"="non-leaf"
+// BKEY-SAME: "sign-return-address-key"="b_key"
+// BKEY: !"branch-target-enforcement", i32 0
+// BKEY: !"sign-return-address", i32 1
+// BKEY: !"branch-protection-pauth-lr", i32 0
+// BKEY: !"sign-return-address-all", i32 0
+// BKEY: !"sign-return-address-with-bkey", i32 1
+
+// PAUTHLR: attributes [[ATTR]] = {{.*}} "sign-return-address"="non-leaf"
+// PAUTHLR-SAME: "sign-return-address-key"="a_key"
+// PAUTHLR: !"branch-target-enforcement", i32 0
+// PAUTHLR: !"sign-return-address", i32 1
+// PAUTHLR: !"branch-protection-pauth-lr", i32 1
+// PAUTHLR: !"sign-return-address-all", i32 0
+// PAUTHLR: !"sign-return-address-with-bkey", i32 0
+
+// PAUTHLR_BKEY: attributes [[ATTR]] = {{.*}} "sign-return-address"="non-leaf"
+// PAUTHLR_BKEY-SAME: "sign-return-address-key"="b_key"
+// PAUTHLR_BKEY: !"branch-target-enforcement", i32 0
+// PAUTHLR_BKEY: !"sign-return-address", i32 1
+// PAUTHLR_BKEY: !"branch-protection-pauth-lr", i32 1
+// PAUTHLR_BKEY: !"sign-return-address-all", i32 0
+// PAUTHLR_BKEY: !"sign-return-address-with-bkey", i32 1
+
+// PAUTHLR_LEAF: attributes [[ATTR]] = {{.*}} "sign-return-address"="all"
+// PAUTHLR_LEAF-SAME: "sign-return-address-key"="a_key"
+// PAUTHLR_LEAF: !"branch-target-enforcement", i32 0
+// PAUTHLR_LEAF: !"sign-return-address", i32 1
+// PAUTHLR_LEAF: !"branch-protection-pauth-lr", i32 1
+// PAUTHLR_LEAF: !"sign-return-address-all", i32 1
+// PAUTHLR_LEAF: !"sign-return-address-with-bkey", i32 0
+
+// PAUTHLR_BTI: attributes [[ATTR]] = {{.*}} "sign-return-address"="non-leaf"
+// PAUTHLR_BTI-SAME: "sign-return-address-key"="a_key"
+// PAUTHLR_BTI: !"branch-target-enforcement", i32 1
+// PAUTHLR_BTI: !"sign-return-address", i32 1
+// PAUTHLR_BTI: !"branch-protection-pauth-lr", i32 1
+// PAUTHLR_BTI: !"sign-return-address-all", i32 0
+// PAUTHLR_BTI: !"sign-return-address-with-bkey", i32 0
+
+// NONE-NOT: branch-target-enforcement
+// NONE-NOT: sign-return-address
+// NONE-NOT: sign-return-address-all
+// NONE-NOT: sign-return-address-with-bkey
diff --git a/tests/codegen-llvm/call-llvm-intrinsics.rs b/tests/codegen-llvm/call-llvm-intrinsics.rs
new file mode 100644
index 00000000000..dc7e0249cb6
--- /dev/null
+++ b/tests/codegen-llvm/call-llvm-intrinsics.rs
@@ -0,0 +1,30 @@
+//@ compile-flags: -C no-prepopulate-passes -Copt-level=0
+
+//@ ignore-riscv64
+//@ ignore-loongarch64
+
+#![feature(link_llvm_intrinsics)]
+#![crate_type = "lib"]
+
+struct A;
+
+impl Drop for A {
+    fn drop(&mut self) {
+        println!("A");
+    }
+}
+
+extern "C" {
+    #[link_name = "llvm.sqrt.f32"]
+    fn sqrt(x: f32) -> f32;
+}
+
+pub fn do_call() {
+    let _a = A;
+
+    unsafe {
+        // Ensure that we `call` LLVM intrinsics instead of trying to `invoke` them
+        // CHECK: call float @llvm.sqrt.f32(float 4.000000e+00
+        sqrt(4.0);
+    }
+}
diff --git a/tests/codegen-llvm/call-tmps-lifetime.rs b/tests/codegen-llvm/call-tmps-lifetime.rs
new file mode 100644
index 00000000000..7b7b6e17bdd
--- /dev/null
+++ b/tests/codegen-llvm/call-tmps-lifetime.rs
@@ -0,0 +1,68 @@
+// Test that temporary allocas used for call arguments have their lifetimes described by
+// intrinsics.
+//
+//@ add-core-stubs
+//@ compile-flags: -Copt-level=1 -Cno-prepopulate-passes --crate-type=lib --target i686-unknown-linux-gnu
+//@ needs-llvm-components: x86
+#![feature(no_core)]
+#![no_std]
+#![no_core]
+extern crate minicore;
+use minicore::*;
+
+// Const operand. Regression test for #98156.
+//
+// CHECK-LABEL: define void @const_indirect(
+// CHECK-NEXT: start:
+// CHECK-NEXT: [[B:%.*]] = alloca
+// CHECK-NEXT: [[A:%.*]] = alloca
+// CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 4096, ptr [[A]])
+// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[A]], ptr align 4 {{.*}}, i32 4096, i1 false)
+// CHECK-NEXT: call void %h(ptr {{.*}} [[A]])
+// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 4096, ptr [[A]])
+// CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 4096, ptr [[B]])
+// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[B]], ptr align 4 {{.*}}, i32 4096, i1 false)
+// CHECK-NEXT: call void %h(ptr {{.*}} [[B]])
+// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 4096, ptr [[B]])
+#[no_mangle]
+pub fn const_indirect(h: extern "C" fn([u32; 1024])) {
+    const C: [u32; 1024] = [0; 1024];
+    h(C);
+    h(C);
+}
+
+#[repr(C)]
+pub struct Str {
+    pub ptr: *const u8,
+    pub len: usize,
+}
+
+// Pair of immediates. Regression test for #132014.
+//
+// CHECK-LABEL: define void @immediate_indirect(ptr {{.*}}%s.0, i32 {{.*}}%s.1, ptr {{.*}}%g)
+// CHECK-NEXT: start:
+// CHECK-NEXT: [[A:%.*]] = alloca
+// CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 8, ptr [[A]])
+// CHECK-NEXT: store ptr %s.0, ptr [[A]]
+// CHECK-NEXT: [[B:%.]] = getelementptr inbounds i8, ptr [[A]], i32 4
+// CHECK-NEXT: store i32 %s.1, ptr [[B]]
+// CHECK-NEXT: call void %g(ptr {{.*}} [[A]])
+// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[A]])
+#[no_mangle]
+pub fn immediate_indirect(s: Str, g: extern "C" fn(Str)) {
+    g(s);
+}
+
+// Indirect argument with a higher alignment requirement than the type's.
+//
+// CHECK-LABEL: define void @align_indirect(ptr{{.*}} align 1{{.*}} %a, ptr{{.*}} %fun)
+// CHECK-NEXT: start:
+// CHECK-NEXT: [[A:%.*]] = alloca [1024 x i8], align 4
+// CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 1024, ptr [[A]])
+// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[A]], ptr align 1 %a, i32 1024, i1 false)
+// CHECK-NEXT: call void %fun(ptr {{.*}} [[A]])
+// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 1024, ptr [[A]])
+#[no_mangle]
+pub fn align_indirect(a: [u8; 1024], fun: extern "C" fn([u8; 1024])) {
+    fun(a);
+}
diff --git a/tests/codegen-llvm/cast-optimized.rs b/tests/codegen-llvm/cast-optimized.rs
new file mode 100644
index 00000000000..11220c4a922
--- /dev/null
+++ b/tests/codegen-llvm/cast-optimized.rs
@@ -0,0 +1,33 @@
+//@ compile-flags: -Copt-level=3 -Z merge-functions=disabled
+#![crate_type = "lib"]
+
+// This tests that LLVM can optimize based on the niches in the source or
+// destination types for casts.
+
+// CHECK-LABEL: @u32_index
+#[no_mangle]
+pub fn u32_index(c: u32) -> [bool; 22] {
+    let mut array = [false; 22];
+
+    let index = 32 - c.leading_zeros();
+
+    // CHECK: call core::panicking::panic
+    array[index as usize] = true;
+
+    array
+}
+
+// CHECK-LABEL: @char_as_u32_index
+#[no_mangle]
+pub fn char_as_u32_index(c: char) -> [bool; 22] {
+    let c = c as u32;
+
+    let mut array = [false; 22];
+
+    let index = 32 - c.leading_zeros();
+
+    // CHECK-NOT: call core::panicking::panic
+    array[index as usize] = true;
+
+    array
+}
diff --git a/tests/codegen-llvm/cast-target-abi.rs b/tests/codegen-llvm/cast-target-abi.rs
new file mode 100644
index 00000000000..cbd49e2f022
--- /dev/null
+++ b/tests/codegen-llvm/cast-target-abi.rs
@@ -0,0 +1,599 @@
+// ignore-tidy-linelength
+//@ add-core-stubs
+//@ revisions:aarch64 loongarch64 powerpc64 sparc64 x86_64
+//@ compile-flags: -Copt-level=3 -Cno-prepopulate-passes -Zlint-llvm-ir
+
+//@[aarch64] compile-flags: --target aarch64-unknown-linux-gnu
+//@[aarch64] needs-llvm-components: arm
+//@[loongarch64] compile-flags: --target loongarch64-unknown-linux-gnu
+//@[loongarch64] needs-llvm-components: loongarch
+//@[powerpc64] compile-flags: --target powerpc64-unknown-linux-gnu
+//@[powerpc64] needs-llvm-components: powerpc
+//@[sparc64] compile-flags: --target sparc64-unknown-linux-gnu
+//@[sparc64] needs-llvm-components: sparc
+//@[x86_64] compile-flags: --target x86_64-unknown-linux-gnu
+//@[x86_64] needs-llvm-components: x86
+
+// Tests that arguments with `PassMode::Cast` are handled correctly.
+
+#![feature(no_core, lang_items)]
+#![crate_type = "lib"]
+#![no_std]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+// This struct will be passed as a single `i64` or `i32`.
+// This may be (if `i64)) larger than the Rust layout, which is just `{ i16, i16 }`.
+#[repr(C)]
+pub struct TwoU16s {
+    a: u16,
+    b: u16,
+}
+
+// This struct will be passed as `[2 x i64]`.
+// This is larger than the Rust layout.
+#[repr(C)]
+pub struct FiveU16s {
+    a: u16,
+    b: u16,
+    c: u16,
+    d: u16,
+    e: u16,
+}
+
+// This struct will be passed as `[2 x double]`.
+// This is the same as the Rust layout.
+#[repr(C)]
+pub struct DoubleDouble {
+    f: f64,
+    g: f64,
+}
+
+// On loongarch, this struct will be passed as `{ double, float }`.
+// This is smaller than the Rust layout, which has trailing padding (`{ f64, f32, <f32 padding> }`)
+#[repr(C)]
+pub struct DoubleFloat {
+    f: f64,
+    g: f32,
+}
+
+// On x86_64, this struct will be passed as `{ i64, i32 }`.
+// The load and store instructions will access 16 bytes, so we should allocate 16 bytes.
+#[repr(C)]
+pub struct Three32s {
+    a: u32,
+    b: u32,
+    c: u32,
+}
+
+// CHECK-LABEL: @receives_twou16s
+// aarch64-SAME:     ([[ABI_TYPE:i64]] {{.*}}[[ABI_VALUE:%.+]])
+// loongarch64-SAME: ([[ABI_TYPE:i64]] {{.*}}[[ABI_VALUE:%.+]])
+// powerpc64-SAME:   ([[ABI_TYPE:i32]] {{.*}}[[ABI_VALUE:%.+]])
+// sparc64-SAME:     ([[ABI_TYPE:i64]] {{.*}}[[ABI_VALUE:%.+]])
+// x86_64-SAME:      ([[ABI_TYPE:i32]] {{.*}}[[ABI_VALUE:%.+]])
+#[no_mangle]
+#[inline(never)]
+pub extern "C" fn receives_twou16s(x: TwoU16s) {
+    // aarch64:     [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]]
+    // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]]
+    // powerpc64:   [[ABI_ALLOCA:%.+]] = alloca [4 x i8], align [[ABI_ALIGN:4]]
+    // sparc64:     [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]]
+    // x86_64:      [[ABI_ALLOCA:%.+]] = alloca [4 x i8], align [[ABI_ALIGN:4]]
+
+    // CHECK: [[RUST_ALLOCA:%.+]] = alloca [4 x i8], align [[RUST_ALIGN:2]]
+
+    // CHECK: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+
+    // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 4, i1 false)
+}
+
+// CHECK-LABEL: @returns_twou16s
+// powerpc64-SAME: sret([4 x i8]) align [[RUST_ALIGN:2]] {{.*}}[[RET_PTR:%.*]])
+#[no_mangle]
+#[inline(never)]
+pub extern "C" fn returns_twou16s() -> TwoU16s {
+    // powerpc returns this struct via sret pointer, it doesn't use the cast ABI.
+    // The other targets copy the cast ABI type to an alloca.
+
+    // aarch64:     [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:2]]
+    // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:2]]
+    // sparc64:     [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:2]]
+    // x86_64:      [[ABI_ALLOCA:%.+]] = alloca [4 x i8], align [[ABI_ALIGN:2]]
+
+    // aarch64:     [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i64]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i64]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // sparc64:     [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i64]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // x86_64:      [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i32]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+
+    // aarch64:     ret [[ABI_TYPE]] [[ABI_VALUE]]
+    // loongarch64: ret [[ABI_TYPE]] [[ABI_VALUE]]
+    // sparc64:     ret [[ABI_TYPE]] [[ABI_VALUE]]
+    // x86_64:      ret [[ABI_TYPE]] [[ABI_VALUE]]
+    TwoU16s { a: 0, b: 1 }
+}
+
+// CHECK-LABEL: @receives_fiveu16s
+// aarch64-SAME:     ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]])
+// loongarch64-SAME: ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]])
+// powerpc64-SAME:   ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]])
+// sparc64-SAME:     ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]])
+// x86_64-SAME:      ([[ABI_TYPE:{ i64, i16 }]] {{.*}}[[ABI_VALUE:%.+]])
+#[no_mangle]
+#[inline(never)]
+pub extern "C" fn receives_fiveu16s(x: FiveU16s) {
+    // CHECK: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+
+    // CHECK: [[RUST_ALLOCA:%.+]] = alloca [10 x i8], align [[RUST_ALIGN:2]]
+
+    // CHECK: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+
+    // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 10, i1 false)
+}
+
+// CHECK-LABEL: @returns_fiveu16s
+// powerpc64-SAME: sret([10 x i8]) align [[RUST_ALIGN:2]] {{.*}}[[RET_PTR:%.*]])
+#[no_mangle]
+#[inline(never)]
+pub extern "C" fn returns_fiveu16s() -> FiveU16s {
+    // powerpc returns this struct via sret pointer, it doesn't use the cast ABI.
+    // The other targets copy the cast ABI type to an alloca.
+
+    // aarch64:     [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:2]]
+    // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:2]]
+    // sparc64:     [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:2]]
+    // x86_64:      [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:2]]
+
+    // aarch64:     [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // sparc64:     [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // x86_64:      [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ i64, i16 }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+
+    // aarch64:     ret [[ABI_TYPE]] [[ABI_VALUE]]
+    // loongarch64: ret [[ABI_TYPE]] [[ABI_VALUE]]
+    // sparc64:     ret [[ABI_TYPE]] [[ABI_VALUE]]
+    // x86_64:      ret [[ABI_TYPE]] [[ABI_VALUE]]
+    FiveU16s { a: 0, b: 1, c: 2, d: 3, e: 4 }
+}
+
+// CHECK-LABEL: @receives_doubledouble
+// aarch64-SAME:     ([[ABI_TYPE:\[2 x double\]]] {{.*}}[[ABI_VALUE:%.+]])
+// loongarch64-SAME: ([[ABI_TYPE:{ double, double }]] {{.*}}[[ABI_VALUE:%.+]])
+// powerpc64-SAME:   ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]])
+// sparc64-SAME:     ([[ABI_TYPE:{ double, double }]] {{.*}}[[ABI_VALUE:%.+]])
+// x86_64-SAME:      ([[ABI_TYPE:{ double, double }]] {{.*}}[[ABI_VALUE:%.+]])
+#[no_mangle]
+#[inline(never)]
+pub extern "C" fn receives_doubledouble(x: DoubleDouble) {
+    // CHECK: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+
+    // CHECK: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]]
+
+    // CHECK: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+
+    // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false)
+}
+
+// CHECK-LABEL: @returns_doubledouble
+// powerpc64-SAME: sret([16 x i8]) align [[RUST_ALIGN:8]] {{.*}}[[RET_PTR:%.*]])
+#[no_mangle]
+#[inline(never)]
+pub extern "C" fn returns_doubledouble() -> DoubleDouble {
+    // powerpc returns this struct via sret pointer, it doesn't use the cast ABI.
+    // The other targets copy the cast ABI type to an alloca.
+
+    // aarch64:     [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+    // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+    // sparc64:     [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+    // x86_64:      [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+
+    // aarch64:     [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x double\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // sparc64:     [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // x86_64:      [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+
+    // aarch64:     ret [[ABI_TYPE]] [[ABI_VALUE]]
+    // loongarch64: ret [[ABI_TYPE]] [[ABI_VALUE]]
+    // sparc64:     ret [[ABI_TYPE]] [[ABI_VALUE]]
+    // x86_64:      ret [[ABI_TYPE]] [[ABI_VALUE]]
+    DoubleDouble { f: 0., g: 1. }
+}
+
+// CHECK-LABEL: @receives_three32s
+// aarch64-SAME:     ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]])
+// loongarch64-SAME: ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]])
+// powerpc64-SAME:   ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]])
+// sparc64-SAME:     ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]])
+// x86_64-SAME:      ([[ABI_TYPE:{ i64, i32 }]] {{.*}}[[ABI_VALUE:%.+]])
+#[no_mangle]
+#[inline(never)]
+pub extern "C" fn receives_three32s(x: Three32s) {
+    // CHECK: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+
+    // CHECK: [[RUST_ALLOCA:%.+]] = alloca [12 x i8], align [[RUST_ALIGN:4]]
+
+    // CHECK: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+
+    // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 12, i1 false)
+}
+
+// CHECK-LABEL: @returns_three32s
+// powerpc64-SAME: sret([12 x i8]) align [[RUST_ALIGN:4]] {{.*}}[[RET_PTR:%.*]])
+#[no_mangle]
+#[inline(never)]
+pub extern "C" fn returns_three32s() -> Three32s {
+    // powerpc returns this struct via sret pointer, it doesn't use the cast ABI.
+    // The other targets copy the cast ABI type to an alloca.
+
+    // aarch64:     [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:4]]
+    // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:4]]
+    // sparc64:     [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:4]]
+    // x86_64:      [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:4]]
+
+    // aarch64:     [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // sparc64:     [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // x86_64:      [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ i64, i32 }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+
+    // aarch64:     ret [[ABI_TYPE]] [[ABI_VALUE]]
+    // loongarch64: ret [[ABI_TYPE]] [[ABI_VALUE]]
+    // sparc64:     ret [[ABI_TYPE]] [[ABI_VALUE]]
+    // x86_64:      ret [[ABI_TYPE]] [[ABI_VALUE]]
+    Three32s { a: 0, b: 0, c: 0 }
+}
+
+// These functions cause an ICE in sparc64 ABI code (https://github.com/rust-lang/rust/issues/122620)
+#[cfg(not(target_arch = "sparc64"))]
+// aarch64-LABEL:     @receives_doublefloat
+// loongarch64-LABEL: @receives_doublefloat
+// powerpc64-LABEL:   @receives_doublefloat
+// x86_64-LABEL:      @receives_doublefloat
+
+// aarch64-SAME:     ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]])
+// loongarch64-SAME: ([[ABI_TYPE:{ double, float }]] {{.*}}[[ABI_VALUE:%.+]])
+// powerpc64-SAME:   ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]])
+// x86_64-SAME:      ([[ABI_TYPE:{ double, double }]] {{.*}}[[ABI_VALUE:%.+]])
+#[no_mangle]
+#[inline(never)]
+pub extern "C" fn receives_doublefloat(x: DoubleFloat) {
+    // aarch64:     [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+    // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+    // powerpc64:   [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+    // x86_64:      [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+
+    // aarch64:     [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]]
+    // loongarch64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]]
+    // powerpc64:   [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]]
+    // x86_64:      [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]]
+
+    // aarch64:     store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // powerpc64:   store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // x86_64:      store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+
+    // aarch64:     call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false)
+    // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 12, i1 false)
+    // powerpc64:   call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false)
+    // x86_64:      call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false)
+}
+
+#[cfg(not(target_arch = "sparc64"))]
+// aarch64-LABEL:     @returns_doublefloat
+// loongarch64-LABEL: @returns_doublefloat
+// powerpc64-LABEL:   @returns_doublefloat
+// x86_64-LABEL:      @returns_doublefloat
+
+// powerpc64-SAME: sret([16 x i8]) align [[RUST_ALIGN:8]] {{.*}}[[RET_PTR:%.*]])
+#[no_mangle]
+#[inline(never)]
+pub extern "C" fn returns_doublefloat() -> DoubleFloat {
+    // powerpc returns this struct via sret pointer, it doesn't use the cast ABI.
+    // The other targets copy the cast ABI type to an alloca.
+
+    // aarch64:     [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+    // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+    // x86_64:      [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+
+    // aarch64:     [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, float }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // x86_64:      [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+
+    // aarch64:     ret [[ABI_TYPE]] [[ABI_VALUE]]
+    // loongarch64: ret [[ABI_TYPE]] [[ABI_VALUE]]
+    // x86_64:      ret [[ABI_TYPE]] [[ABI_VALUE]]
+    DoubleFloat { f: 0., g: 0. }
+}
+
+// CHECK-LABEL: @call_twou16s
+#[no_mangle]
+pub fn call_twou16s() {
+    // aarch64:     [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]]
+    // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]]
+    // powerpc64:   [[ABI_ALLOCA:%.+]] = alloca [4 x i8], align [[ABI_ALIGN:4]]
+    // sparc64:     [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]]
+    // x86_64:      [[ABI_ALLOCA:%.+]] = alloca [4 x i8], align [[ABI_ALIGN:4]]
+
+    // CHECK: [[RUST_ALLOCA:%.+]] = alloca [4 x i8], align [[RUST_ALIGN:2]]
+
+    // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 4, i1 false)
+
+    // aarch64:     [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i64]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i64]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // powerpc64:   [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i32]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // sparc64:     [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i64]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // x86_64:      [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i32]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+
+    // CHECK: call void @receives_twou16s([[ABI_TYPE]] [[ABI_VALUE]])
+    let x = TwoU16s { a: 1, b: 2 };
+    receives_twou16s(x);
+}
+
+// CHECK-LABEL: @return_twou16s
+#[no_mangle]
+pub fn return_twou16s() -> TwoU16s {
+    // powerpc returns this struct via sret pointer, it doesn't use the cast ABI.
+
+    // powerpc64: [[RETVAL:%.+]] = alloca [4 x i8], align 2
+    // powerpc64: call void @returns_twou16s(ptr {{.+}} [[RETVAL]])
+
+    // The other targets copy the cast ABI type to an alloca.
+
+    // aarch64:     [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]]
+    // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]]
+    // sparc64:     [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]]
+    // x86_64:      [[ABI_ALLOCA:%.+]] = alloca [4 x i8], align [[ABI_ALIGN:4]]
+
+    // aarch64:     [[RUST_ALLOCA:%.+]] = alloca [4 x i8], align [[RUST_ALIGN:2]]
+    // loongarch64: [[RUST_ALLOCA:%.+]] = alloca [4 x i8], align [[RUST_ALIGN:2]]
+    // sparc64:     [[RUST_ALLOCA:%.+]] = alloca [4 x i8], align [[RUST_ALIGN:2]]
+    // x86_64:      [[RUST_ALLOCA:%.+]] = alloca [4 x i8], align [[RUST_ALIGN:2]]
+
+    // aarch64:     [[ABI_VALUE:%.+]] = call [[ABI_TYPE:i64]] @returns_twou16s()
+    // loongarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:i64]] @returns_twou16s()
+    // sparc64:     [[ABI_VALUE:%.+]] = call [[ABI_TYPE:i64]] @returns_twou16s()
+    // x86_64:      [[ABI_VALUE:%.+]] = call [[ABI_TYPE:i32]] @returns_twou16s()
+
+    // aarch64:     store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // sparc64:     store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // x86_64:      store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+
+    // aarch64:     call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 4, i1 false)
+    // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 4, i1 false)
+    // sparc64:     call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 4, i1 false)
+    // x86_64:      call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 4, i1 false)
+    returns_twou16s()
+}
+
+// CHECK-LABEL: @call_fiveu16s
+#[no_mangle]
+pub fn call_fiveu16s() {
+    // CHECK: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+
+    // CHECK: [[RUST_ALLOCA:%.+]] = alloca [10 x i8], align 2
+
+    // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 10, i1 false)
+
+    // aarch64:     [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // powerpc64:   [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // sparc64:     [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // x86_64:      [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ i64, i16 }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+
+    // CHECK: call void @receives_fiveu16s([[ABI_TYPE]] [[ABI_VALUE]])
+    let x = FiveU16s { a: 1, b: 2, c: 3, d: 4, e: 5 };
+    receives_fiveu16s(x);
+}
+
+// CHECK-LABEL: @return_fiveu16s
+// CHECK-SAME: (ptr {{.+}} sret([10 x i8]) align [[RUST_ALIGN:2]] {{.*}}dereferenceable(10) [[RET_PTR:%.+]])
+#[no_mangle]
+pub fn return_fiveu16s() -> FiveU16s {
+    // powerpc returns this struct via sret pointer, it doesn't use the cast ABI.
+
+    // powerpc64: call void @returns_fiveu16s(ptr {{.+}} [[RET_PTR]])
+
+    // The other targets copy the cast ABI type to the sret pointer.
+
+    // aarch64:     [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+    // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+    // sparc64:     [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+    // x86_64:      [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+
+    // aarch64:     [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x i64\]]] @returns_fiveu16s()
+    // loongarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x i64\]]] @returns_fiveu16s()
+    // sparc64:     [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x i64\]]] @returns_fiveu16s()
+    // x86_64:      [[ABI_VALUE:%.+]] = call [[ABI_TYPE:{ i64, i16 }]] @returns_fiveu16s()
+
+    // aarch64:     store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // sparc64:     store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // x86_64:      store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+
+    // aarch64:     call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RET_PTR]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 10, i1 false)
+    // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RET_PTR]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 10, i1 false)
+    // sparc64:     call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RET_PTR]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 10, i1 false)
+    // x86_64:      call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RET_PTR]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 10, i1 false)
+    returns_fiveu16s()
+}
+
+// CHECK-LABEL: @call_doubledouble
+#[no_mangle]
+pub fn call_doubledouble() {
+    // CHECK: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+
+    // CHECK: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]]
+
+    // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 16, i1 false)
+
+    // aarch64:     [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x double\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // powerpc64:   [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // sparc64:     [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // x86_64:      [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+
+    // CHECK: call void @receives_doubledouble([[ABI_TYPE]] [[ABI_VALUE]])
+    let x = DoubleDouble { f: 1., g: 2. };
+    receives_doubledouble(x);
+}
+
+// CHECK-LABEL: @return_doubledouble
+#[no_mangle]
+pub fn return_doubledouble() -> DoubleDouble {
+    // powerpc returns this struct via sret pointer, it doesn't use the cast ABI.
+
+    // powerpc64: [[RETVAL:%.+]] = alloca [16 x i8], align 8
+    // powerpc64: call void @returns_doubledouble(ptr {{.+}} [[RETVAL]])
+
+    // The other targets copy the cast ABI type to an alloca.
+
+    // aarch64:     [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+    // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+    // sparc64:     [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+    // x86_64:      [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+
+    // aarch64:     [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]]
+    // loongarch64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]]
+    // sparc64:     [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]]
+    // x86_64:      [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]]
+
+    // aarch64:     [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x double\]]] @returns_doubledouble()
+    // loongarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:{ double, double }]] @returns_doubledouble()
+    // sparc64:     [[ABI_VALUE:%.+]] = call [[ABI_TYPE:{ double, double }]] @returns_doubledouble()
+    // x86_64:      [[ABI_VALUE:%.+]] = call [[ABI_TYPE:{ double, double }]] @returns_doubledouble()
+
+    // aarch64:     store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // sparc64:     store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // x86_64:      store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+
+    // aarch64:     call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false)
+    // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false)
+    // sparc64:     call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false)
+    // x86_64:      call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false)
+    returns_doubledouble()
+}
+
+// This test causes an ICE in sparc64 ABI code (https://github.com/rust-lang/rust/issues/122620)
+#[cfg(not(target_arch = "sparc64"))]
+// aarch64-LABEL:     @call_doublefloat
+// loongarch64-LABEL: @call_doublefloat
+// powerpc64-LABEL:   @call_doublefloat
+// x86_64-LABEL:      @call_doublefloat
+#[no_mangle]
+pub fn call_doublefloat() {
+    // aarch64:     [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+    // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+    // powerpc64:   [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+    // x86_64:      [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+
+    // aarch64:     [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]]
+    // loongarch64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]]
+    // powerpc64:   [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]]
+    // x86_64:      [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]]
+
+    // aarch64:     call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 16, i1 false)
+    // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 12, i1 false)
+    // powerpc64:   call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 16, i1 false)
+    // x86_64:      call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 16, i1 false)
+
+    // aarch64:     [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, float }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // powerpc64:   [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // x86_64:      [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+
+    // aarch64:     call void @receives_doublefloat([[ABI_TYPE]] {{(inreg )?}}[[ABI_VALUE]])
+    // loongarch64: call void @receives_doublefloat([[ABI_TYPE]] {{(inreg )?}}[[ABI_VALUE]])
+    // powerpc64:   call void @receives_doublefloat([[ABI_TYPE]] {{(inreg )?}}[[ABI_VALUE]])
+    // x86_64:      call void @receives_doublefloat([[ABI_TYPE]] {{(inreg )?}}[[ABI_VALUE]])
+    let x = DoubleFloat { f: 1., g: 2. };
+    receives_doublefloat(x);
+}
+
+// This test causes an ICE in sparc64 ABI code (https://github.com/rust-lang/rust/issues/122620)
+#[cfg(not(target_arch = "sparc64"))]
+// aarch64-LABEL:     @return_doublefloat
+// loongarch64-LABEL: @return_doublefloat
+// powerpc64-LABEL:   @return_doublefloat
+// x86_64-LABEL:      @return_doublefloat
+#[no_mangle]
+pub fn return_doublefloat() -> DoubleFloat {
+    // powerpc returns this struct via sret pointer, it doesn't use the cast ABI.
+
+    // powerpc64: [[RETVAL:%.+]] = alloca [16 x i8], align 8
+    // powerpc64: call void @returns_doublefloat(ptr {{.+}} [[RETVAL]])
+
+    // The other targets copy the cast ABI type to an alloca.
+
+    // aarch64:     [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+    // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+    // x86_64:      [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+
+    // aarch64:     [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]]
+    // loongarch64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]]
+    // x86_64:      [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]]
+
+    // aarch64:     [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x i64\]]] @returns_doublefloat()
+    // loongarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:{ double, float }]] @returns_doublefloat()
+    // x86_64:      [[ABI_VALUE:%.+]] = call [[ABI_TYPE:{ double, double }]] @returns_doublefloat()
+
+    // aarch64:     store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // x86_64:      store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+
+    // aarch64:     call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false)
+    // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 12, i1 false)
+    // x86_64:      call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false)
+    returns_doublefloat()
+}
+
+// CHECK-LABEL: @call_three32s
+#[no_mangle]
+pub fn call_three32s() {
+    // CHECK: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+    // CHECK: [[RUST_ALLOCA:%.+]] = alloca [12 x i8], align [[RUST_ALIGN:4]]
+    // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 12, i1 false)
+
+    // aarch64:     [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // powerpc64:   [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // sparc64:     [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // x86_64:      [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ i64, i32 }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+
+    // CHECK: call void @receives_three32s([[ABI_TYPE]] [[ABI_VALUE]])
+    let x = Three32s { a: 1, b: 2, c: 3 };
+    receives_three32s(x);
+}
+
+// Regression test for #75839
+// CHECK-LABEL: @return_three32s(
+// CHECK-SAME: sret([12 x i8]) align [[RUST_ALIGN:4]] {{.*}}[[RUST_RETVAL:%.*]])
+#[no_mangle]
+pub fn return_three32s() -> Three32s {
+    // powerpc returns this struct via sret pointer, it doesn't use the cast ABI.
+
+    // powerpc64: call void @returns_three32s(ptr {{.+}} [[RUST_RETVAL]])
+
+    // aarch64:     [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+    // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+    // sparc64:     [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+    // x86_64:      [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+
+    // aarch64:     [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x i64\]]] @returns_three32s()
+    // loongarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x i64\]]] @returns_three32s()
+    // sparc64:     [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x i64\]]] @returns_three32s()
+    // x86_64:      [[ABI_VALUE:%.+]] = call [[ABI_TYPE:{ i64, i32 }]] @returns_three32s()
+
+    // aarch64:     store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // sparc64:     store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // x86_64:      store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+
+    // aarch64:     call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_RETVAL]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 12, i1 false)
+    // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_RETVAL]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 12, i1 false)
+    // sparc64:     call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_RETVAL]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 12, i1 false)
+    // x86_64:      call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_RETVAL]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 12, i1 false)
+    returns_three32s()
+}
diff --git a/tests/codegen-llvm/catch-unwind.rs b/tests/codegen-llvm/catch-unwind.rs
new file mode 100644
index 00000000000..d1ff55bcc28
--- /dev/null
+++ b/tests/codegen-llvm/catch-unwind.rs
@@ -0,0 +1,32 @@
+//@ compile-flags: -Copt-level=3
+
+// On x86 the closure is inlined in foo() producing something like
+// define i32 @foo() [...] {
+// tail call void @bar() [...]
+// ret i32 0
+// }
+// On riscv the closure is another function, placed before fn foo so CHECK can't
+// find it
+//@ ignore-riscv64 FIXME
+// On s390x the closure is also in another function
+//@ ignore-s390x FIXME
+// On loongarch64 the closure is also in another function
+//@ ignore-loongarch64 FIXME
+
+#![crate_type = "lib"]
+
+extern "C" {
+    fn bar();
+}
+
+// CHECK-LABEL: @foo
+#[no_mangle]
+pub unsafe fn foo() -> i32 {
+    // CHECK: call void @bar
+    // CHECK: ret i32 0
+    std::panic::catch_unwind(|| {
+        bar();
+        0
+    })
+    .unwrap()
+}
diff --git a/tests/codegen-llvm/cdylib-external-inline-fns.rs b/tests/codegen-llvm/cdylib-external-inline-fns.rs
new file mode 100644
index 00000000000..2e472ea68e8
--- /dev/null
+++ b/tests/codegen-llvm/cdylib-external-inline-fns.rs
@@ -0,0 +1,43 @@
+//@ compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "cdylib"]
+
+// CHECK: define{{( dso_local)?}} void @a()
+#[no_mangle]
+#[inline]
+pub extern "C" fn a() {}
+
+// CHECK: define{{( dso_local)?}} void @b()
+#[export_name = "b"]
+#[inline]
+pub extern "C" fn b() {}
+
+// CHECK: define{{( dso_local)?}} void @c()
+#[no_mangle]
+#[inline]
+extern "C" fn c() {}
+
+// CHECK: define{{( dso_local)?}} void @d()
+#[export_name = "d"]
+#[inline]
+extern "C" fn d() {}
+
+// CHECK: define{{( dso_local)?}} void @e()
+#[no_mangle]
+#[inline(always)]
+pub extern "C" fn e() {}
+
+// CHECK: define{{( dso_local)?}} void @f()
+#[export_name = "f"]
+#[inline(always)]
+pub extern "C" fn f() {}
+
+// CHECK: define{{( dso_local)?}} void @g()
+#[no_mangle]
+#[inline(always)]
+extern "C" fn g() {}
+
+// CHECK: define{{( dso_local)?}} void @h()
+#[export_name = "h"]
+#[inline(always)]
+extern "C" fn h() {}
diff --git a/tests/codegen-llvm/cf-protection.rs b/tests/codegen-llvm/cf-protection.rs
new file mode 100644
index 00000000000..f1349a5dcb9
--- /dev/null
+++ b/tests/codegen-llvm/cf-protection.rs
@@ -0,0 +1,38 @@
+// Test that the correct module flags are emitted with different control-flow protection flags.
+
+//@ add-core-stubs
+//@ revisions: undefined none branch return full
+//@ needs-llvm-components: x86
+//@ [undefined] compile-flags:
+//@ [none] compile-flags: -Z cf-protection=none
+//@ [branch] compile-flags: -Z cf-protection=branch
+//@ [return] compile-flags: -Z cf-protection=return
+//@ [full] compile-flags: -Z cf-protection=full
+//@ compile-flags: --target x86_64-unknown-linux-gnu
+
+#![crate_type = "lib"]
+#![feature(no_core, lang_items)]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+// A basic test function.
+pub fn test() {}
+
+// undefined-NOT: !"cf-protection-branch"
+// undefined-NOT: !"cf-protection-return"
+
+// none-NOT: !"cf-protection-branch"
+// none-NOT: !"cf-protection-return"
+
+// branch-NOT: !"cf-protection-return"
+// branch: !"cf-protection-branch", i32 1
+// branch-NOT: !"cf-protection-return"
+
+// return-NOT: !"cf-protection-branch"
+// return: !"cf-protection-return", i32 1
+// return-NOT: !"cf-protection-branch"
+
+// full: !"cf-protection-branch", i32 1
+// full: !"cf-protection-return", i32 1
diff --git a/tests/codegen-llvm/cffi/c-variadic-copy.rs b/tests/codegen-llvm/cffi/c-variadic-copy.rs
new file mode 100644
index 00000000000..4c61c4fcf68
--- /dev/null
+++ b/tests/codegen-llvm/cffi/c-variadic-copy.rs
@@ -0,0 +1,16 @@
+// Tests that `VaListImpl::clone` gets inlined into a call to `llvm.va_copy`
+
+#![crate_type = "lib"]
+#![feature(c_variadic)]
+#![no_std]
+use core::ffi::VaList;
+
+extern "C" {
+    fn foreign_c_variadic_1(_: VaList, ...);
+}
+
+pub unsafe extern "C" fn clone_variadic(ap: VaList) {
+    let mut ap2 = ap.clone();
+    // CHECK: call void @llvm.va_copy
+    foreign_c_variadic_1(ap2.as_va_list(), 42i32);
+}
diff --git a/tests/codegen-llvm/cffi/c-variadic-naked.rs b/tests/codegen-llvm/cffi/c-variadic-naked.rs
new file mode 100644
index 00000000000..5843628b633
--- /dev/null
+++ b/tests/codegen-llvm/cffi/c-variadic-naked.rs
@@ -0,0 +1,15 @@
+//@ needs-asm-support
+//@ only-x86_64
+
+// tests that `va_start` is not injected into naked functions
+
+#![crate_type = "lib"]
+#![feature(c_variadic)]
+#![no_std]
+
+#[unsafe(naked)]
+pub unsafe extern "C" fn c_variadic(_: usize, _: ...) {
+    // CHECK-NOT: va_start
+    // CHECK-NOT: alloca
+    core::arch::naked_asm!("ret")
+}
diff --git a/tests/codegen-llvm/cffi/c-variadic-opt.rs b/tests/codegen-llvm/cffi/c-variadic-opt.rs
new file mode 100644
index 00000000000..7e544ee7f37
--- /dev/null
+++ b/tests/codegen-llvm/cffi/c-variadic-opt.rs
@@ -0,0 +1,30 @@
+//@ compile-flags: -C opt-level=3
+
+#![crate_type = "lib"]
+#![feature(c_variadic)]
+#![no_std]
+use core::ffi::VaList;
+
+extern "C" {
+    fn vprintf(fmt: *const i8, ap: VaList) -> i32;
+}
+
+// Ensure that `va_start` and `va_end` are properly injected even
+// when the "spoofed" `VaListImpl` is not used.
+#[no_mangle]
+pub unsafe extern "C" fn c_variadic_no_use(fmt: *const i8, mut ap: ...) -> i32 {
+    // CHECK: call void @llvm.va_start
+    vprintf(fmt, ap.as_va_list())
+    // CHECK: call void @llvm.va_end
+}
+
+// Check that `VaListImpl::clone` gets inlined into a direct call to `llvm.va_copy`
+#[no_mangle]
+pub unsafe extern "C" fn c_variadic_clone(fmt: *const i8, mut ap: ...) -> i32 {
+    // CHECK: call void @llvm.va_start
+    let mut ap2 = ap.clone();
+    // CHECK: call void @llvm.va_copy
+    let res = vprintf(fmt, ap2.as_va_list());
+    res
+    // CHECK: call void @llvm.va_end
+}
diff --git a/tests/codegen-llvm/cffi/c-variadic.rs b/tests/codegen-llvm/cffi/c-variadic.rs
new file mode 100644
index 00000000000..140d2f37f46
--- /dev/null
+++ b/tests/codegen-llvm/cffi/c-variadic.rs
@@ -0,0 +1,71 @@
+//@ needs-unwind
+//@ compile-flags: -C no-prepopulate-passes -Copt-level=0
+//
+
+#![crate_type = "lib"]
+#![feature(c_variadic)]
+#![no_std]
+use core::ffi::VaList;
+
+extern "C" {
+    fn foreign_c_variadic_0(_: i32, ...);
+    fn foreign_c_variadic_1(_: VaList, ...);
+}
+
+pub unsafe extern "C" fn use_foreign_c_variadic_0() {
+    // Ensure that we correctly call foreign C-variadic functions.
+    // CHECK: call void (i32, ...) @foreign_c_variadic_0([[PARAM:i32( signext)?]] 0)
+    foreign_c_variadic_0(0);
+    // CHECK: call void (i32, ...) @foreign_c_variadic_0([[PARAM]] 0, [[PARAM]] 42)
+    foreign_c_variadic_0(0, 42i32);
+    // CHECK: call void (i32, ...) @foreign_c_variadic_0([[PARAM]] 0, [[PARAM]] 42, [[PARAM]] 1024)
+    foreign_c_variadic_0(0, 42i32, 1024i32);
+    // CHECK: call void (i32, ...) @foreign_c_variadic_0([[PARAM]] 0, [[PARAM]] 42, [[PARAM]] 1024, [[PARAM]] 0)
+    foreign_c_variadic_0(0, 42i32, 1024i32, 0i32);
+}
+
+// Ensure that we do not remove the `va_list` passed to the foreign function when
+// removing the "spoofed" `VaListImpl` that is used by Rust defined C-variadics.
+pub unsafe extern "C" fn use_foreign_c_variadic_1_0(ap: VaList) {
+    // CHECK: call void ({{.*}}, ...) @foreign_c_variadic_1({{.*}} %ap)
+    foreign_c_variadic_1(ap);
+}
+
+pub unsafe extern "C" fn use_foreign_c_variadic_1_1(ap: VaList) {
+    // CHECK: call void ({{.*}}, ...) @foreign_c_variadic_1({{.*}} %ap, [[PARAM]] 42)
+    foreign_c_variadic_1(ap, 42i32);
+}
+pub unsafe extern "C" fn use_foreign_c_variadic_1_2(ap: VaList) {
+    // CHECK: call void ({{.*}}, ...) @foreign_c_variadic_1({{.*}} %ap, [[PARAM]] 2, [[PARAM]] 42)
+    foreign_c_variadic_1(ap, 2i32, 42i32);
+}
+
+pub unsafe extern "C" fn use_foreign_c_variadic_1_3(ap: VaList) {
+    // CHECK: call void ({{.*}}, ...) @foreign_c_variadic_1({{.*}} %ap, [[PARAM]] 2, [[PARAM]] 42, [[PARAM]] 0)
+    foreign_c_variadic_1(ap, 2i32, 42i32, 0i32);
+}
+
+// Ensure that `va_start` and `va_end` are properly injected.
+#[no_mangle]
+pub unsafe extern "C" fn c_variadic(n: i32, mut ap: ...) -> i32 {
+    // CHECK: call void @llvm.va_start
+    let mut sum = 0;
+    for _ in 0..n {
+        sum += ap.arg::<i32>();
+    }
+    sum
+    // CHECK: call void @llvm.va_end
+}
+
+// Ensure that we generate the correct `call` signature when calling a Rust
+// defined C-variadic.
+pub unsafe fn test_c_variadic_call() {
+    // CHECK: call [[RET:(signext )?i32]] (i32, ...) @c_variadic([[PARAM]] 0)
+    c_variadic(0);
+    // CHECK: call [[RET]] (i32, ...) @c_variadic([[PARAM]] 0, [[PARAM]] 42)
+    c_variadic(0, 42i32);
+    // CHECK: call [[RET]] (i32, ...) @c_variadic([[PARAM]] 0, [[PARAM]] 42, [[PARAM]] 1024)
+    c_variadic(0, 42i32, 1024i32);
+    // CHECK: call [[RET]] (i32, ...) @c_variadic([[PARAM]] 0, [[PARAM]] 42, [[PARAM]] 1024, [[PARAM]] 0)
+    c_variadic(0, 42i32, 1024i32, 0i32);
+}
diff --git a/tests/codegen-llvm/cffi/ffi-const.rs b/tests/codegen-llvm/cffi/ffi-const.rs
new file mode 100644
index 00000000000..3ea9d517ec2
--- /dev/null
+++ b/tests/codegen-llvm/cffi/ffi-const.rs
@@ -0,0 +1,15 @@
+//@ compile-flags: -C no-prepopulate-passes
+#![crate_type = "lib"]
+#![feature(ffi_const)]
+
+pub fn bar() {
+    unsafe { foo() }
+}
+
+extern "C" {
+    // CHECK-LABEL: declare{{.*}}void @foo()
+    // CHECK-SAME: [[ATTRS:#[0-9]+]]
+    // CHECK-DAG: attributes [[ATTRS]] = { {{.*}}memory(none){{.*}} }
+    #[unsafe(ffi_const)]
+    pub fn foo();
+}
diff --git a/tests/codegen-llvm/cffi/ffi-out-of-bounds-loads.rs b/tests/codegen-llvm/cffi/ffi-out-of-bounds-loads.rs
new file mode 100644
index 00000000000..859386d2df8
--- /dev/null
+++ b/tests/codegen-llvm/cffi/ffi-out-of-bounds-loads.rs
@@ -0,0 +1,41 @@
+//@ add-core-stubs
+//@ revisions: linux apple
+//@ compile-flags: -Copt-level=0 -Cno-prepopulate-passes -Zlint-llvm-ir
+
+//@[linux] compile-flags: --target x86_64-unknown-linux-gnu
+//@[linux] needs-llvm-components: x86
+//@[apple] compile-flags: --target x86_64-apple-darwin
+//@[apple] needs-llvm-components: x86
+
+// Regression test for #29988
+
+#![feature(no_core, lang_items)]
+#![crate_type = "lib"]
+#![no_std]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+#[repr(C)]
+struct S {
+    f1: i32,
+    f2: i32,
+    f3: i32,
+}
+
+extern "C" {
+    fn foo(s: S);
+}
+
+// CHECK-LABEL: @test
+#[no_mangle]
+pub fn test() {
+    let s = S { f1: 1, f2: 2, f3: 3 };
+    unsafe {
+        // CHECK: [[ALLOCA:%.+]] = alloca [16 x i8], align 8
+        // CHECK: [[LOAD:%.+]] = load { i64, i32 }, ptr [[ALLOCA]], align 8
+        // CHECK: call void @foo({ i64, i32 } [[LOAD]])
+        foo(s);
+    }
+}
diff --git a/tests/codegen-llvm/cffi/ffi-pure.rs b/tests/codegen-llvm/cffi/ffi-pure.rs
new file mode 100644
index 00000000000..a61e80ecf65
--- /dev/null
+++ b/tests/codegen-llvm/cffi/ffi-pure.rs
@@ -0,0 +1,15 @@
+//@ compile-flags: -C no-prepopulate-passes
+#![crate_type = "lib"]
+#![feature(ffi_pure)]
+
+pub fn bar() {
+    unsafe { foo() }
+}
+
+extern "C" {
+    // CHECK-LABEL: declare{{.*}}void @foo()
+    // CHECK-SAME: [[ATTRS:#[0-9]+]]
+    // CHECK-DAG: attributes [[ATTRS]] = { {{.*}}memory(read){{.*}} }
+    #[unsafe(ffi_pure)]
+    pub fn foo();
+}
diff --git a/tests/codegen-llvm/cfguard-checks.rs b/tests/codegen-llvm/cfguard-checks.rs
new file mode 100644
index 00000000000..cdf6406ad61
--- /dev/null
+++ b/tests/codegen-llvm/cfguard-checks.rs
@@ -0,0 +1,10 @@
+//@ compile-flags: -C control-flow-guard=checks
+//@ only-msvc
+
+#![crate_type = "lib"]
+
+// A basic test function.
+pub fn test() {}
+
+// Ensure the module flag cfguard=2 is present
+// CHECK: !"cfguard", i32 2
diff --git a/tests/codegen-llvm/cfguard-disabled.rs b/tests/codegen-llvm/cfguard-disabled.rs
new file mode 100644
index 00000000000..90915c0f0c6
--- /dev/null
+++ b/tests/codegen-llvm/cfguard-disabled.rs
@@ -0,0 +1,10 @@
+//@ compile-flags: -C control-flow-guard=no
+//@ only-msvc
+
+#![crate_type = "lib"]
+
+// A basic test function.
+pub fn test() {}
+
+// Ensure the module flag cfguard is not present
+// CHECK-NOT: !"cfguard"
diff --git a/tests/codegen-llvm/cfguard-nochecks.rs b/tests/codegen-llvm/cfguard-nochecks.rs
new file mode 100644
index 00000000000..5f386533ec1
--- /dev/null
+++ b/tests/codegen-llvm/cfguard-nochecks.rs
@@ -0,0 +1,10 @@
+//@ compile-flags: -C control-flow-guard=nochecks
+//@ only-msvc
+
+#![crate_type = "lib"]
+
+// A basic test function.
+pub fn test() {}
+
+// Ensure the module flag cfguard=1 is present
+// CHECK: !"cfguard", i32 1
diff --git a/tests/codegen-llvm/cfguard-non-msvc.rs b/tests/codegen-llvm/cfguard-non-msvc.rs
new file mode 100644
index 00000000000..1e6559aaf5d
--- /dev/null
+++ b/tests/codegen-llvm/cfguard-non-msvc.rs
@@ -0,0 +1,10 @@
+//@ compile-flags: -C control-flow-guard
+//@ ignore-msvc
+
+#![crate_type = "lib"]
+
+// A basic test function.
+pub fn test() {}
+
+// Ensure the cfguard module flag is not added for non-MSVC targets.
+// CHECK-NOT: !"cfguard"
diff --git a/tests/codegen-llvm/char-ascii-branchless.rs b/tests/codegen-llvm/char-ascii-branchless.rs
new file mode 100644
index 00000000000..f99066aa9aa
--- /dev/null
+++ b/tests/codegen-llvm/char-ascii-branchless.rs
@@ -0,0 +1,47 @@
+// Checks that these functions are branchless.
+//
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @is_ascii_alphanumeric_char
+#[no_mangle]
+pub fn is_ascii_alphanumeric_char(x: char) -> bool {
+    // CHECK-NOT: br
+    x.is_ascii_alphanumeric()
+}
+
+// CHECK-LABEL: @is_ascii_alphanumeric_u8
+#[no_mangle]
+pub fn is_ascii_alphanumeric_u8(x: u8) -> bool {
+    // CHECK-NOT: br
+    x.is_ascii_alphanumeric()
+}
+
+// CHECK-LABEL: @is_ascii_hexdigit_char
+#[no_mangle]
+pub fn is_ascii_hexdigit_char(x: char) -> bool {
+    // CHECK-NOT: br
+    x.is_ascii_hexdigit()
+}
+
+// CHECK-LABEL: @is_ascii_hexdigit_u8
+#[no_mangle]
+pub fn is_ascii_hexdigit_u8(x: u8) -> bool {
+    // CHECK-NOT: br
+    x.is_ascii_hexdigit()
+}
+
+// CHECK-LABEL: @is_ascii_punctuation_char
+#[no_mangle]
+pub fn is_ascii_punctuation_char(x: char) -> bool {
+    // CHECK-NOT: br
+    x.is_ascii_punctuation()
+}
+
+// CHECK-LABEL: @is_ascii_punctuation_u8
+#[no_mangle]
+pub fn is_ascii_punctuation_u8(x: u8) -> bool {
+    // CHECK-NOT: br
+    x.is_ascii_punctuation()
+}
diff --git a/tests/codegen-llvm/char-escape-debug-no-bounds-check.rs b/tests/codegen-llvm/char-escape-debug-no-bounds-check.rs
new file mode 100644
index 00000000000..cfde46045e5
--- /dev/null
+++ b/tests/codegen-llvm/char-escape-debug-no-bounds-check.rs
@@ -0,0 +1,14 @@
+//@ compile-flags: -Copt-level=3
+#![crate_type = "lib"]
+
+use std::char::EscapeDebug;
+
+// Make sure no bounds checks are emitted when escaping a character.
+
+// CHECK-LABEL: @char_escape_debug_no_bounds_check
+#[no_mangle]
+pub fn char_escape_debug_no_bounds_check(c: char) -> EscapeDebug {
+    // CHECK-NOT: panic
+    // CHECK-NOT: panic_bounds_check
+    c.escape_debug()
+}
diff --git a/tests/codegen-llvm/checked_ilog.rs b/tests/codegen-llvm/checked_ilog.rs
new file mode 100644
index 00000000000..e340a45b6a9
--- /dev/null
+++ b/tests/codegen-llvm/checked_ilog.rs
@@ -0,0 +1,20 @@
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+
+// Ensure that when val < base, we do not divide or multiply.
+
+// CHECK-LABEL: @checked_ilog
+// CHECK-SAME: (i16{{.*}} %val, i16{{.*}} %base)
+#[no_mangle]
+pub fn checked_ilog(val: u16, base: u16) -> Option<u32> {
+    // CHECK-NOT: udiv
+    // CHECK-NOT: mul
+    // CHECK: %[[IS_LESS:.+]] = icmp ult i16 %val, %base
+    // CHECK-NEXT: br i1 %[[IS_LESS]], label %[[TRUE:.+]], label %[[FALSE:.+]]
+    // CHECK: [[TRUE]]:
+    // CHECK-NOT: udiv
+    // CHECK-NOT: mul
+    // CHECK: ret { i32, i32 }
+    val.checked_ilog(base)
+}
diff --git a/tests/codegen-llvm/checked_math.rs b/tests/codegen-llvm/checked_math.rs
new file mode 100644
index 00000000000..66667c69488
--- /dev/null
+++ b/tests/codegen-llvm/checked_math.rs
@@ -0,0 +1,100 @@
+//@ compile-flags: -Copt-level=3 -Z merge-functions=disabled
+
+#![crate_type = "lib"]
+#![feature(unchecked_shifts)]
+
+// Because the result of something like `u32::checked_sub` can only be used if it
+// didn't overflow, make sure that LLVM actually knows that in optimized builds.
+// Thanks to poison semantics, this doesn't even need branches.
+
+// CHECK-LABEL: @checked_sub_unsigned
+// CHECK-SAME: (i16{{.*}} %a, i16{{.*}} %b)
+#[no_mangle]
+pub fn checked_sub_unsigned(a: u16, b: u16) -> Option<u16> {
+    // CHECK-DAG: %[[IS_SOME:.+]] = icmp uge i16 %a, %b
+    // CHECK-DAG: %[[DIFF_P:.+]] = sub nuw i16 %a, %b
+    // CHECK-DAG: %[[DISCR:.+]] = zext i1 %[[IS_SOME]] to i16
+    // CHECK-DAG: %[[DIFF_U:.+]] = select i1 %[[IS_SOME]], i16 %[[DIFF_P]], i16 undef
+
+    // CHECK: %[[R0:.+]] = insertvalue { i16, i16 } poison, i16 %[[DISCR]], 0
+    // CHECK: %[[R1:.+]] = insertvalue { i16, i16 } %[[R0]], i16 %[[DIFF_U]], 1
+    // CHECK: ret { i16, i16 } %[[R1]]
+    a.checked_sub(b)
+}
+
+// Note that `shl` and `shr` in LLVM are already unchecked. So rather than
+// looking for no-wrap flags, we just need there to not be any masking.
+
+// CHECK-LABEL: @checked_shl_unsigned
+// CHECK-SAME: (i32{{.*}} %a, i32{{.*}} %b)
+#[no_mangle]
+pub fn checked_shl_unsigned(a: u32, b: u32) -> Option<u32> {
+    // CHECK-DAG: %[[IS_SOME:.+]] = icmp ult i32 %b, 32
+    // CHECK-DAG: %[[SHIFTED_P:.+]] = shl i32 %a, %b
+    // CHECK-DAG: %[[DISCR:.+]] = zext i1 %[[IS_SOME]] to i32
+    // CHECK-DAG: %[[SHIFTED_U:.+]] = select i1 %[[IS_SOME]], i32 %[[SHIFTED_P]], i32 undef
+
+    // CHECK: %[[R0:.+]] = insertvalue { i32, i32 } poison, i32 %[[DISCR]], 0
+    // CHECK: %[[R1:.+]] = insertvalue { i32, i32 } %[[R0]], i32 %[[SHIFTED_U]], 1
+    // CHECK: ret { i32, i32 } %[[R1]]
+    a.checked_shl(b)
+}
+
+// CHECK-LABEL: @checked_shr_unsigned
+// CHECK-SAME: (i32{{.*}} %a, i32{{.*}} %b)
+#[no_mangle]
+pub fn checked_shr_unsigned(a: u32, b: u32) -> Option<u32> {
+    // CHECK-DAG: %[[IS_SOME:.+]] = icmp ult i32 %b, 32
+    // CHECK-DAG: %[[SHIFTED_P:.+]] = lshr i32 %a, %b
+    // CHECK-DAG: %[[DISCR:.+]] = zext i1 %[[IS_SOME]] to i32
+    // CHECK-DAG: %[[SHIFTED_U:.+]] = select i1 %[[IS_SOME]], i32 %[[SHIFTED_P]], i32 undef
+
+    // CHECK: %[[R0:.+]] = insertvalue { i32, i32 } poison, i32 %[[DISCR]], 0
+    // CHECK: %[[R1:.+]] = insertvalue { i32, i32 } %[[R0]], i32 %[[SHIFTED_U]], 1
+    // CHECK: ret { i32, i32 } %[[R1]]
+    a.checked_shr(b)
+}
+
+// CHECK-LABEL: @checked_shl_signed
+// CHECK-SAME: (i32{{.*}} %a, i32{{.*}} %b)
+#[no_mangle]
+pub fn checked_shl_signed(a: i32, b: u32) -> Option<i32> {
+    // CHECK-DAG: %[[IS_SOME:.+]] = icmp ult i32 %b, 32
+    // CHECK-DAG: %[[SHIFTED_P:.+]] = shl i32 %a, %b
+    // CHECK-DAG: %[[DISCR:.+]] = zext i1 %[[IS_SOME]] to i32
+    // CHECK-DAG: %[[SHIFTED_U:.+]] = select i1 %[[IS_SOME]], i32 %[[SHIFTED_P]], i32 undef
+
+    // CHECK: %[[R0:.+]] = insertvalue { i32, i32 } poison, i32 %[[DISCR]], 0
+    // CHECK: %[[R1:.+]] = insertvalue { i32, i32 } %[[R0]], i32 %[[SHIFTED_U]], 1
+    // CHECK: ret { i32, i32 } %[[R1]]
+    a.checked_shl(b)
+}
+
+// CHECK-LABEL: @checked_shr_signed
+// CHECK-SAME: (i32{{.*}} %a, i32{{.*}} %b)
+#[no_mangle]
+pub fn checked_shr_signed(a: i32, b: u32) -> Option<i32> {
+    // CHECK-DAG: %[[IS_SOME:.+]] = icmp ult i32 %b, 32
+    // CHECK-DAG: %[[SHIFTED_P:.+]] = ashr i32 %a, %b
+    // CHECK-DAG: %[[DISCR:.+]] = zext i1 %[[IS_SOME]] to i32
+    // CHECK-DAG: %[[SHIFTED_U:.+]] = select i1 %[[IS_SOME]], i32 %[[SHIFTED_P]], i32 undef
+
+    // CHECK: %[[R0:.+]] = insertvalue { i32, i32 } poison, i32 %[[DISCR]], 0
+    // CHECK: %[[R1:.+]] = insertvalue { i32, i32 } %[[R0]], i32 %[[SHIFTED_U]], 1
+    // CHECK: ret { i32, i32 } %[[R1]]
+    a.checked_shr(b)
+}
+
+// CHECK-LABEL: @checked_add_one_unwrap_unsigned
+// CHECK-SAME: (i32{{.*}} %x)
+#[no_mangle]
+pub fn checked_add_one_unwrap_unsigned(x: u32) -> u32 {
+    // CHECK: %[[IS_MAX:.+]] = icmp eq i32 %x, -1
+    // CHECK: br i1 %[[IS_MAX]], label %[[NONE_BB:.+]], label %[[SOME_BB:.+]],
+    // CHECK: [[SOME_BB]]:
+    // CHECK: %[[R:.+]] = add nuw i32 %x, 1
+    // CHECK: ret i32 %[[R]]
+    // CHECK: [[NONE_BB]]:
+    // CHECK: call {{.+}}unwrap_failed
+    x.checked_add(1).unwrap()
+}
diff --git a/tests/codegen-llvm/clone-shims.rs b/tests/codegen-llvm/clone-shims.rs
new file mode 100644
index 00000000000..06c959f9ee7
--- /dev/null
+++ b/tests/codegen-llvm/clone-shims.rs
@@ -0,0 +1,15 @@
+// Clone shims for aggregates are generated by just calling the Clone shims for all their members.
+// Those calls generate a lot of unnecessary IR if the members are Copy. This test ensures that we
+// optimize away those inner calls without needing to inline them.
+
+//@ compile-flags: -Cno-prepopulate-passes -Csymbol-mangling-version=v0 -Zinline-mir=no
+#![crate_type = "lib"]
+
+pub type Test = (i32, i32, *const i32);
+pub static TEST: fn(&Test) -> Test = <Test as core::clone::Clone>::clone;
+
+// CHECK-NOT: call <i32 as core::clone::Clone>::clone
+// CHECK-NOT: call <*const i32 as core::clone::Clone>::clone
+// CHECK:     ; <(i32, i32, *const i32) as core::clone::Clone>::clone
+// CHECK-NOT: call <i32 as core::clone::Clone>::clone
+// CHECK-NOT: call <*const i32 as core::clone::Clone>::clone
diff --git a/tests/codegen-llvm/clone_as_copy.rs b/tests/codegen-llvm/clone_as_copy.rs
new file mode 100644
index 00000000000..ef834ef5912
--- /dev/null
+++ b/tests/codegen-llvm/clone_as_copy.rs
@@ -0,0 +1,40 @@
+//@ revisions: DEBUGINFO NODEBUGINFO
+//@ compile-flags: -Copt-level=3 -Cno-prepopulate-passes
+//@ [DEBUGINFO] compile-flags: -Cdebuginfo=full
+
+// From https://github.com/rust-lang/rust/issues/128081.
+// Ensure that we only generate a memcpy instruction.
+
+#![crate_type = "lib"]
+
+#[derive(Clone)]
+struct SubCloneAndCopy {
+    v1: u32,
+    v2: u32,
+}
+
+#[derive(Clone)]
+struct CloneOnly {
+    v1: u8,
+    v2: u8,
+    v3: u8,
+    v4: u8,
+    v5: u8,
+    v6: u8,
+    v7: u8,
+    v8: u8,
+    v9: u8,
+    v_sub: SubCloneAndCopy,
+    v_large: [u8; 256],
+}
+
+// CHECK-LABEL: define {{.*}}@clone_only(
+#[no_mangle]
+pub fn clone_only(v: &CloneOnly) -> CloneOnly {
+    // CHECK-NOT: call {{.*}}clone
+    // CHECK-NOT: store i8
+    // CHECK-NOT: store i32
+    // CHECK: call void @llvm.memcpy
+    // CHECK-NEXT: ret void
+    v.clone()
+}
diff --git a/tests/codegen-llvm/codemodels.rs b/tests/codegen-llvm/codemodels.rs
new file mode 100644
index 00000000000..06d2eade78a
--- /dev/null
+++ b/tests/codegen-llvm/codemodels.rs
@@ -0,0 +1,20 @@
+//@ only-x86_64
+
+//@ revisions: NOMODEL MODEL-SMALL MODEL-KERNEL MODEL-MEDIUM MODEL-LARGE
+//@[NOMODEL] compile-flags:
+//@[MODEL-SMALL] compile-flags: -C code-model=small
+//@[MODEL-KERNEL] compile-flags: -C code-model=kernel
+//@[MODEL-MEDIUM] compile-flags: -C code-model=medium
+//@[MODEL-LARGE] compile-flags: -C code-model=large
+
+#![crate_type = "lib"]
+
+// MODEL-SMALL: !llvm.module.flags = !{{{.*}}}
+// MODEL-SMALL: !{{[0-9]+}} = !{i32 1, !"Code Model", i32 1}
+// MODEL-KERNEL: !llvm.module.flags = !{{{.*}}}
+// MODEL-KERNEL: !{{[0-9]+}} = !{i32 1, !"Code Model", i32 2}
+// MODEL-MEDIUM: !llvm.module.flags = !{{{.*}}}
+// MODEL-MEDIUM: !{{[0-9]+}} = !{i32 1, !"Code Model", i32 3}
+// MODEL-LARGE: !llvm.module.flags = !{{{.*}}}
+// MODEL-LARGE: !{{[0-9]+}} = !{i32 1, !"Code Model", i32 4}
+// NOMODEL-NOT: Code Model
diff --git a/tests/codegen-llvm/coercions.rs b/tests/codegen-llvm/coercions.rs
new file mode 100644
index 00000000000..63c1742c639
--- /dev/null
+++ b/tests/codegen-llvm/coercions.rs
@@ -0,0 +1,19 @@
+//@ compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+static X: i32 = 5;
+
+// CHECK-LABEL: @raw_ptr_to_raw_ptr_noop
+// CHECK-NOT: alloca
+#[no_mangle]
+pub fn raw_ptr_to_raw_ptr_noop() -> *const i32 {
+    &X as *const i32
+}
+
+// CHECK-LABEL: @reference_to_raw_ptr_noop
+// CHECK-NOT: alloca
+#[no_mangle]
+pub fn reference_to_raw_ptr_noop() -> *const i32 {
+    &X
+}
diff --git a/tests/codegen-llvm/cold-call-declare-and-call.rs b/tests/codegen-llvm/cold-call-declare-and-call.rs
new file mode 100644
index 00000000000..b18565ee6c3
--- /dev/null
+++ b/tests/codegen-llvm/cold-call-declare-and-call.rs
@@ -0,0 +1,27 @@
+//@ revisions: NORMAL WIN
+//@ compile-flags: -C no-prepopulate-passes
+//@[NORMAL] ignore-windows
+//@[WIN] only-windows
+//@[WIN] only-x86_64
+
+#![crate_type = "lib"]
+#![feature(rust_cold_cc)]
+
+// wasm marks the definition as `dso_local`, so allow that as optional.
+
+// NORMAL: define{{( dso_local)?}} preserve_mostcc void @this_should_never_happen(i16
+// NORMAL: call preserve_mostcc void @this_should_never_happen(i16
+
+// See the comment in `Target::adjust_abi` for why this differs
+
+// WIN: define void @this_should_never_happen(i16
+// WIN: call void @this_should_never_happen(i16
+
+#[no_mangle]
+pub extern "rust-cold" fn this_should_never_happen(x: u16) {}
+
+pub fn do_things(x: u16) {
+    if x == 12345 {
+        this_should_never_happen(54321);
+    }
+}
diff --git a/tests/codegen-llvm/common_prim_int_ptr.rs b/tests/codegen-llvm/common_prim_int_ptr.rs
new file mode 100644
index 00000000000..53716adccbf
--- /dev/null
+++ b/tests/codegen-llvm/common_prim_int_ptr.rs
@@ -0,0 +1,51 @@
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+// Tests that codegen works properly when enums like `Result<usize, Box<()>>`
+// are represented as `{ u64, ptr }`, i.e., for `Ok(123)`, `123` is stored
+// as a pointer.
+
+// CHECK-LABEL: @insert_int
+#[no_mangle]
+pub fn insert_int(x: usize) -> Result<usize, Box<()>> {
+    // CHECK: start:
+    // CHECK-NEXT: %[[WO_PROV:.+]] = getelementptr i8, ptr null, [[USIZE:i[0-9]+]] %x
+    // CHECK-NEXT: %[[R:.+]] = insertvalue { [[USIZE]], ptr } { [[USIZE]] 0, ptr poison }, ptr %[[WO_PROV]], 1
+    // CHECK-NEXT: ret { [[USIZE]], ptr } %[[R]]
+    Ok(x)
+}
+
+// CHECK-LABEL: @insert_box
+#[no_mangle]
+pub fn insert_box(x: Box<()>) -> Result<usize, Box<()>> {
+    // CHECK: start:
+    // CHECK-NEXT: insertvalue { i{{[0-9]+}}, ptr }
+    // CHECK-NEXT: ret
+    Err(x)
+}
+
+// CHECK-LABEL: @extract_int
+// CHECK-NOT: nonnull
+// CHECK-SAME: (i{{[0-9]+}} {{[^%]+}} [[DISCRIMINANT:%[0-9]+]], ptr {{[^,]+}} [[PAYLOAD:%[0-9]+]])
+#[no_mangle]
+pub unsafe fn extract_int(x: Result<usize, Box<()>>) -> usize {
+    // CHECK: [[TEMP:%.+]] = ptrtoint ptr [[PAYLOAD]] to [[USIZE:i[0-9]+]]
+    // CHECK: ret [[USIZE]] [[TEMP]]
+    match x {
+        Ok(v) => v,
+        Err(_) => std::intrinsics::unreachable(),
+    }
+}
+
+// CHECK-LABEL: @extract_box
+// CHECK-SAME: (i{{[0-9]+}} {{[^%]+}} [[DISCRIMINANT:%[0-9]+]], ptr {{[^%]+}} [[PAYLOAD:%[0-9]+]])
+#[no_mangle]
+pub unsafe fn extract_box(x: Result<usize, Box<i32>>) -> Box<i32> {
+    // CHECK: ret ptr [[PAYLOAD]]
+    match x {
+        Ok(_) => std::intrinsics::unreachable(),
+        Err(e) => e,
+    }
+}
diff --git a/tests/codegen-llvm/comparison-operators-2-struct.rs b/tests/codegen-llvm/comparison-operators-2-struct.rs
new file mode 100644
index 00000000000..e179066ebfd
--- /dev/null
+++ b/tests/codegen-llvm/comparison-operators-2-struct.rs
@@ -0,0 +1,61 @@
+//@ compile-flags: -C opt-level=1
+//@ min-llvm-version: 20
+
+// The `derive(PartialOrd)` for a 2-field type doesn't override `lt`/`le`/`gt`/`ge`.
+// This double-checks that the `Option<Ordering>` intermediate values used
+// in the operators for such a type all optimize away.
+
+#![crate_type = "lib"]
+
+use std::cmp::Ordering;
+
+#[derive(PartialOrd, PartialEq)]
+pub struct Foo(i32, u32);
+
+// CHECK-LABEL: @check_lt(
+// CHECK-SAME: i32{{.+}}%[[A0:.+]], i32{{.+}}%[[A1:.+]], i32{{.+}}%[[B0:.+]], i32{{.+}}%[[B1:.+]])
+#[no_mangle]
+pub fn check_lt(a: Foo, b: Foo) -> bool {
+    // CHECK-DAG: %[[EQ:.+]] = icmp eq i32 %[[A0]], %[[B0]]
+    // CHECK-DAG: %[[R0:.+]] = icmp slt i32 %[[A0]], %[[B0]]
+    // CHECK-DAG: %[[R1:.+]] = icmp ult i32 %[[A1]], %[[B1]]
+    // CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[R1]], i1 %[[R0]]
+    // CHECK-NEXT: ret i1 %[[R]]
+    a < b
+}
+
+// CHECK-LABEL: @check_le(
+// CHECK-SAME: i32{{.+}}%[[A0:.+]], i32{{.+}}%[[A1:.+]], i32{{.+}}%[[B0:.+]], i32{{.+}}%[[B1:.+]])
+#[no_mangle]
+pub fn check_le(a: Foo, b: Foo) -> bool {
+    // CHECK-DAG: %[[EQ:.+]] = icmp eq i32 %[[A0]], %[[B0]]
+    // CHECK-DAG: %[[R0:.+]] = icmp sle i32 %[[A0]], %[[B0]]
+    // CHECK-DAG: %[[R1:.+]] = icmp ule i32 %[[A1]], %[[B1]]
+    // CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[R1]], i1 %[[R0]]
+    // CHECK-NEXT: ret i1 %[[R]]
+    a <= b
+}
+
+// CHECK-LABEL: @check_gt(
+// CHECK-SAME: i32{{.+}}%[[A0:.+]], i32{{.+}}%[[A1:.+]], i32{{.+}}%[[B0:.+]], i32{{.+}}%[[B1:.+]])
+#[no_mangle]
+pub fn check_gt(a: Foo, b: Foo) -> bool {
+    // CHECK-DAG: %[[EQ:.+]] = icmp eq i32 %[[A0]], %[[B0]]
+    // CHECK-DAG: %[[R0:.+]] = icmp sgt i32 %[[A0]], %[[B0]]
+    // CHECK-DAG: %[[R1:.+]] = icmp ugt i32 %[[A1]], %[[B1]]
+    // CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[R1]], i1 %[[R0]]
+    // CHECK-NEXT: ret i1 %[[R]]
+    a > b
+}
+
+// CHECK-LABEL: @check_ge(
+// CHECK-SAME: i32{{.+}}%[[A0:.+]], i32{{.+}}%[[A1:.+]], i32{{.+}}%[[B0:.+]], i32{{.+}}%[[B1:.+]])
+#[no_mangle]
+pub fn check_ge(a: Foo, b: Foo) -> bool {
+    // CHECK-DAG: %[[EQ:.+]] = icmp eq i32 %[[A0]], %[[B0]]
+    // CHECK-DAG: %[[R0:.+]] = icmp sge i32 %[[A0]], %[[B0]]
+    // CHECK-DAG: %[[R1:.+]] = icmp uge i32 %[[A1]], %[[B1]]
+    // CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[R1]], i1 %[[R0]]
+    // CHECK-NEXT: ret i1 %[[R]]
+    a >= b
+}
diff --git a/tests/codegen-llvm/comparison-operators-2-tuple.rs b/tests/codegen-llvm/comparison-operators-2-tuple.rs
new file mode 100644
index 00000000000..6a7e489c82d
--- /dev/null
+++ b/tests/codegen-llvm/comparison-operators-2-tuple.rs
@@ -0,0 +1,117 @@
+//@ compile-flags: -C opt-level=1 -Z merge-functions=disabled
+//@ min-llvm-version: 20
+
+#![crate_type = "lib"]
+
+use std::cmp::Ordering;
+
+type TwoTuple = (i16, u16);
+
+//
+// The operators are all overridden directly, so should optimize easily.
+//
+// slt-vs-sle and sgt-vs-sge don't matter because they're only used in the side
+// of the select where we know the values are not equal, and thus the tests
+// use a regex to allow either, since unimportant changes to the implementation
+// sometimes result in changing what LLVM decides to emit for this.
+//
+
+// CHECK-LABEL: @check_lt_direct
+// CHECK-SAME: (i16 noundef %[[A0:.+]], i16 noundef %[[A1:.+]], i16 noundef %[[B0:.+]], i16 noundef %[[B1:.+]])
+#[no_mangle]
+pub fn check_lt_direct(a: TwoTuple, b: TwoTuple) -> bool {
+    // CHECK-DAG: %[[EQ:.+]] = icmp eq i16 %[[A0]], %[[B0]]
+    // CHECK-DAG: %[[CMP0:.+]] = icmp {{slt|sle}} i16 %[[A0]], %[[B0]]
+    // CHECK-DAG: %[[CMP1:.+]] = icmp ult i16 %[[A1]], %[[B1]]
+    // CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[CMP1]], i1 %[[CMP0]]
+    // CHECK: ret i1 %[[R]]
+    a < b
+}
+
+// CHECK-LABEL: @check_le_direct
+// CHECK-SAME: (i16 noundef %[[A0:.+]], i16 noundef %[[A1:.+]], i16 noundef %[[B0:.+]], i16 noundef %[[B1:.+]])
+#[no_mangle]
+pub fn check_le_direct(a: TwoTuple, b: TwoTuple) -> bool {
+    // CHECK-DAG: %[[EQ:.+]] = icmp eq i16 %[[A0]], %[[B0]]
+    // CHECK-DAG: %[[CMP0:.+]] = icmp {{slt|sle}} i16 %[[A0]], %[[B0]]
+    // CHECK-DAG: %[[CMP1:.+]] = icmp ule i16 %[[A1]], %[[B1]]
+    // CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[CMP1]], i1 %[[CMP0]]
+    // CHECK: ret i1 %[[R]]
+    a <= b
+}
+
+// CHECK-LABEL: @check_gt_direct
+// CHECK-SAME: (i16 noundef %[[A0:.+]], i16 noundef %[[A1:.+]], i16 noundef %[[B0:.+]], i16 noundef %[[B1:.+]])
+#[no_mangle]
+pub fn check_gt_direct(a: TwoTuple, b: TwoTuple) -> bool {
+    // CHECK-DAG: %[[EQ:.+]] = icmp eq i16 %[[A0]], %[[B0]]
+    // CHECK-DAG: %[[CMP0:.+]] = icmp {{sgt|sge}} i16 %[[A0]], %[[B0]]
+    // CHECK-DAG: %[[CMP1:.+]] = icmp ugt i16 %[[A1]], %[[B1]]
+    // CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[CMP1]], i1 %[[CMP0]]
+    // CHECK: ret i1 %[[R]]
+    a > b
+}
+
+// CHECK-LABEL: @check_ge_direct
+// CHECK-SAME: (i16 noundef %[[A0:.+]], i16 noundef %[[A1:.+]], i16 noundef %[[B0:.+]], i16 noundef %[[B1:.+]])
+#[no_mangle]
+pub fn check_ge_direct(a: TwoTuple, b: TwoTuple) -> bool {
+    // CHECK-DAG: %[[EQ:.+]] = icmp eq i16 %[[A0]], %[[B0]]
+    // CHECK-DAG: %[[CMP0:.+]] = icmp {{sgt|sge}} i16 %[[A0]], %[[B0]]
+    // CHECK-DAG: %[[CMP1:.+]] = icmp uge i16 %[[A1]], %[[B1]]
+    // CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[CMP1]], i1 %[[CMP0]]
+    // CHECK: ret i1 %[[R]]
+    a >= b
+}
+
+//
+// These used to not optimize as well, but thanks to LLVM 20 they work now 🎉
+//
+
+// CHECK-LABEL: @check_lt_via_cmp
+// CHECK-SAME: (i16 noundef %[[A0:.+]], i16 noundef %[[A1:.+]], i16 noundef %[[B0:.+]], i16 noundef %[[B1:.+]])
+#[no_mangle]
+pub fn check_lt_via_cmp(a: TwoTuple, b: TwoTuple) -> bool {
+    // CHECK-DAG: %[[EQ:.+]] = icmp eq i16 %[[A0]], %[[B0]]
+    // CHECK-DAG: %[[CMP0:.+]] = icmp slt i16 %[[A0]], %[[B0]]
+    // CHECK-DAG: %[[CMP1:.+]] = icmp ult i16 %[[A1]], %[[B1]]
+    // CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[CMP1]], i1 %[[CMP0]]
+    // CHECK: ret i1 %[[R]]
+    Ord::cmp(&a, &b).is_lt()
+}
+
+// CHECK-LABEL: @check_le_via_cmp
+// CHECK-SAME: (i16 noundef %[[A0:.+]], i16 noundef %[[A1:.+]], i16 noundef %[[B0:.+]], i16 noundef %[[B1:.+]])
+#[no_mangle]
+pub fn check_le_via_cmp(a: TwoTuple, b: TwoTuple) -> bool {
+    // CHECK-DAG: %[[EQ:.+]] = icmp eq i16 %[[A0]], %[[B0]]
+    // CHECK-DAG: %[[CMP0:.+]] = icmp sle i16 %[[A0]], %[[B0]]
+    // CHECK-DAG: %[[CMP1:.+]] = icmp ule i16 %[[A1]], %[[B1]]
+    // CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[CMP1]], i1 %[[CMP0]]
+    // CHECK: ret i1 %[[R]]
+    Ord::cmp(&a, &b).is_le()
+}
+
+// CHECK-LABEL: @check_gt_via_cmp
+// CHECK-SAME: (i16 noundef %[[A0:.+]], i16 noundef %[[A1:.+]], i16 noundef %[[B0:.+]], i16 noundef %[[B1:.+]])
+#[no_mangle]
+pub fn check_gt_via_cmp(a: TwoTuple, b: TwoTuple) -> bool {
+    // CHECK-DAG: %[[EQ:.+]] = icmp eq i16 %[[A0]], %[[B0]]
+    // CHECK-DAG: %[[CMP0:.+]] = icmp sgt i16 %[[A0]], %[[B0]]
+    // CHECK-DAG: %[[CMP1:.+]] = icmp ugt i16 %[[A1]], %[[B1]]
+    // CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[CMP1]], i1 %[[CMP0]]
+    // CHECK: ret i1 %[[R]]
+    Ord::cmp(&a, &b).is_gt()
+}
+
+// CHECK-LABEL: @check_ge_via_cmp
+// CHECK-SAME: (i16 noundef %[[A0:.+]], i16 noundef %[[A1:.+]], i16 noundef %[[B0:.+]], i16 noundef %[[B1:.+]])
+#[no_mangle]
+pub fn check_ge_via_cmp(a: TwoTuple, b: TwoTuple) -> bool {
+    // CHECK-DAG: %[[EQ:.+]] = icmp eq i16 %[[A0]], %[[B0]]
+    // CHECK-DAG: %[[CMP0:.+]] = icmp sge i16 %[[A0]], %[[B0]]
+    // CHECK-DAG: %[[CMP1:.+]] = icmp uge i16 %[[A1]], %[[B1]]
+    // CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[CMP1]], i1 %[[CMP0]]
+    // CHECK: ret i1 %[[R]]
+    Ord::cmp(&a, &b).is_ge()
+}
diff --git a/tests/codegen-llvm/comparison-operators-newtype.rs b/tests/codegen-llvm/comparison-operators-newtype.rs
new file mode 100644
index 00000000000..acce0cb5946
--- /dev/null
+++ b/tests/codegen-llvm/comparison-operators-newtype.rs
@@ -0,0 +1,48 @@
+// The `derive(PartialOrd)` for a newtype doesn't override `lt`/`le`/`gt`/`ge`.
+// This double-checks that the `Option<Ordering>` intermediate values used
+// in the operators for such a type all optimize away.
+
+//@ compile-flags: -C opt-level=1
+
+#![crate_type = "lib"]
+
+use std::cmp::Ordering;
+
+#[derive(PartialOrd, PartialEq)]
+pub struct Foo(u16);
+
+// CHECK-LABEL: @check_lt
+// CHECK-SAME: (i16{{.*}} %[[A:.+]], i16{{.*}} %[[B:.+]])
+#[no_mangle]
+pub fn check_lt(a: Foo, b: Foo) -> bool {
+    // CHECK: %[[R:.+]] = icmp ult i16 %[[A]], %[[B]]
+    // CHECK-NEXT: ret i1 %[[R]]
+    a < b
+}
+
+// CHECK-LABEL: @check_le
+// CHECK-SAME: (i16{{.*}} %[[A:.+]], i16{{.*}} %[[B:.+]])
+#[no_mangle]
+pub fn check_le(a: Foo, b: Foo) -> bool {
+    // CHECK: %[[R:.+]] = icmp ule i16 %[[A]], %[[B]]
+    // CHECK-NEXT: ret i1 %[[R]]
+    a <= b
+}
+
+// CHECK-LABEL: @check_gt
+// CHECK-SAME: (i16{{.*}} %[[A:.+]], i16{{.*}} %[[B:.+]])
+#[no_mangle]
+pub fn check_gt(a: Foo, b: Foo) -> bool {
+    // CHECK: %[[R:.+]] = icmp ugt i16 %[[A]], %[[B]]
+    // CHECK-NEXT: ret i1 %[[R]]
+    a > b
+}
+
+// CHECK-LABEL: @check_ge
+// CHECK-SAME: (i16{{.*}} %[[A:.+]], i16{{.*}} %[[B:.+]])
+#[no_mangle]
+pub fn check_ge(a: Foo, b: Foo) -> bool {
+    // CHECK: %[[R:.+]] = icmp uge i16 %[[A]], %[[B]]
+    // CHECK-NEXT: ret i1 %[[R]]
+    a >= b
+}
diff --git a/tests/codegen-llvm/compiletest-self-test/minicore-smoke-test.rs b/tests/codegen-llvm/compiletest-self-test/minicore-smoke-test.rs
new file mode 100644
index 00000000000..9dd1bf29c6c
--- /dev/null
+++ b/tests/codegen-llvm/compiletest-self-test/minicore-smoke-test.rs
@@ -0,0 +1,20 @@
+//! Basic smoke test for `minicore` test auxiliary.
+
+//@ add-core-stubs
+//@ compile-flags: --target=x86_64-unknown-linux-gnu
+//@ needs-llvm-components: x86
+
+#![crate_type = "lib"]
+#![feature(no_core)]
+#![no_std]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+struct Meow;
+impl Copy for Meow {}
+
+// CHECK-LABEL: meow
+#[no_mangle]
+fn meow() {}
diff --git a/tests/codegen-llvm/const-array.rs b/tests/codegen-llvm/const-array.rs
new file mode 100644
index 00000000000..b3df76c3d8e
--- /dev/null
+++ b/tests/codegen-llvm/const-array.rs
@@ -0,0 +1,15 @@
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+
+const LUT: [u8; 4] = [1, 1, 1, 1];
+
+// CHECK-LABEL: @decode
+#[no_mangle]
+pub fn decode(i: u8) -> u8 {
+    // CHECK: start:
+    // CHECK-NEXT: icmp
+    // CHECK-NEXT: select
+    // CHECK-NEXT: ret
+    if i < 4 { LUT[i as usize] } else { 2 }
+}
diff --git a/tests/codegen-llvm/const-vector.rs b/tests/codegen-llvm/const-vector.rs
new file mode 100644
index 00000000000..a2249f4fff7
--- /dev/null
+++ b/tests/codegen-llvm/const-vector.rs
@@ -0,0 +1,78 @@
+//@ revisions: OPT0 OPT0_S390X
+//@ [OPT0] ignore-s390x
+//@ [OPT0_S390X] only-s390x
+//@ [OPT0] compile-flags: -C no-prepopulate-passes -Copt-level=0
+//@ [OPT0_S390X] compile-flags: -C no-prepopulate-passes -Copt-level=0 -C target-cpu=z13
+
+// This test checks that constants of SIMD type are passed as immediate vectors.
+// We ensure that both vector representations (struct with fields and struct wrapping array) work.
+#![crate_type = "lib"]
+#![feature(abi_unadjusted)]
+#![feature(const_trait_impl)]
+#![feature(repr_simd)]
+#![feature(rustc_attrs)]
+#![feature(simd_ffi)]
+#![feature(arm_target_feature)]
+#![feature(mips_target_feature)]
+#![allow(non_camel_case_types)]
+
+#[path = "../auxiliary/minisimd.rs"]
+mod minisimd;
+use minisimd::{PackedSimd as Simd, f32x2, i8x2};
+
+// The following functions are required for the tests to ensure
+// that they are called with a const vector
+
+extern "unadjusted" {
+    fn test_i8x2(a: i8x2);
+    fn test_i8x2_two_args(a: i8x2, b: i8x2);
+    fn test_i8x2_mixed_args(a: i8x2, c: i32, b: i8x2);
+    fn test_i8x2_arr(a: i8x2);
+    fn test_f32x2(a: f32x2);
+    fn test_f32x2_arr(a: f32x2);
+    fn test_simd(a: Simd<i32, 4>);
+    fn test_simd_unaligned(a: Simd<i32, 3>);
+}
+
+// Ensure the packed variant of the simd struct does not become a const vector
+// if the size is not a power of 2
+// CHECK: %"minisimd::PackedSimd<i32, 3>" = type { [3 x i32] }
+
+#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))]
+#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))]
+#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))]
+#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))]
+pub fn do_call() {
+    unsafe {
+        // CHECK: call void @test_i8x2(<2 x i8> <i8 32, i8 64>
+        test_i8x2(const { i8x2::from_array([32, 64]) });
+
+        // CHECK: call void @test_i8x2_two_args(<2 x i8> <i8 32, i8 64>, <2 x i8> <i8 8, i8 16>
+        test_i8x2_two_args(
+            const { i8x2::from_array([32, 64]) },
+            const { i8x2::from_array([8, 16]) },
+        );
+
+        // CHECK: call void @test_i8x2_mixed_args(<2 x i8> <i8 32, i8 64>, i32 43, <2 x i8> <i8 8, i8 16>
+        test_i8x2_mixed_args(
+            const { i8x2::from_array([32, 64]) },
+            43,
+            const { i8x2::from_array([8, 16]) },
+        );
+
+        // CHECK: call void @test_i8x2_arr(<2 x i8> <i8 32, i8 64>
+        test_i8x2_arr(const { i8x2::from_array([32, 64]) });
+
+        // CHECK: call void @test_f32x2(<2 x float> <float 0x3FD47AE140000000, float 0x3FE47AE140000000>
+        test_f32x2(const { f32x2::from_array([0.32, 0.64]) });
+
+        // CHECK: void @test_f32x2_arr(<2 x float> <float 0x3FD47AE140000000, float 0x3FE47AE140000000>
+        test_f32x2_arr(const { f32x2::from_array([0.32, 0.64]) });
+
+        // CHECK: call void @test_simd(<4 x i32> <i32 2, i32 4, i32 6, i32 8>
+        test_simd(const { Simd::<i32, 4>([2, 4, 6, 8]) });
+
+        // CHECK: call void @test_simd_unaligned(%"minisimd::PackedSimd<i32, 3>" %1
+        test_simd_unaligned(const { Simd::<i32, 3>([2, 4, 6]) });
+    }
+}
diff --git a/tests/codegen-llvm/const_scalar_pair.rs b/tests/codegen-llvm/const_scalar_pair.rs
new file mode 100644
index 00000000000..f142896c31f
--- /dev/null
+++ b/tests/codegen-llvm/const_scalar_pair.rs
@@ -0,0 +1,8 @@
+//@ compile-flags: --crate-type=lib -Copt-level=0 -Zmir-opt-level=0 -C debuginfo=2
+
+// Test that we don't generate a memory allocation for the constant
+// and read the fields from that, but instead just create the value pair directly.
+pub fn foo() -> (i32, i32) {
+    // CHECK: ret { i32, i32 } { i32 1, i32 2 }
+    const { (1, 2) }
+}
diff --git a/tests/codegen-llvm/constant-branch.rs b/tests/codegen-llvm/constant-branch.rs
new file mode 100644
index 00000000000..8fc8fb4f57a
--- /dev/null
+++ b/tests/codegen-llvm/constant-branch.rs
@@ -0,0 +1,49 @@
+//@ compile-flags: -Zmir-opt-level=0 -C no-prepopulate-passes -Copt-level=0
+// make sure that branching on a constant does not emit a conditional
+// branch or a switch
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @if_bool
+#[no_mangle]
+pub fn if_bool() {
+    // CHECK-NOT: br i1
+    // CHECK-NOT: switch
+    _ = if true { 0 } else { 1 };
+
+    _ = if false { 0 } else { 1 };
+}
+
+// CHECK-LABEL: @if_constant_int_eq
+#[no_mangle]
+pub fn if_constant_int_eq() {
+    // CHECK-NOT: br i1
+    // CHECK-NOT: switch
+    let val = 0;
+    _ = if val == 0 { 0 } else { 1 };
+
+    // CHECK: br label %{{.+}}
+    _ = if val == 1 { 0 } else { 1 };
+}
+
+// CHECK-LABEL: @if_constant_match
+#[no_mangle]
+pub fn if_constant_match() {
+    // CHECK-NOT: br i1
+    // CHECK-NOT: switch
+    _ = match 1 {
+        1 => 2,
+        2 => 3,
+        _ => 4,
+    };
+
+    _ = match 1 {
+        2 => 3,
+        _ => 4,
+    };
+
+    _ = match -1 {
+        -1 => 1,
+        _ => 0,
+    }
+}
diff --git a/tests/codegen-llvm/consts.rs b/tests/codegen-llvm/consts.rs
new file mode 100644
index 00000000000..42ce7679d1a
--- /dev/null
+++ b/tests/codegen-llvm/consts.rs
@@ -0,0 +1,55 @@
+//@ compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+// Below, these constants are defined as enum variants that by itself would
+// have a lower alignment than the enum type. Ensure that we mark them
+// correctly with the higher alignment of the enum.
+
+// CHECK: @STATIC = {{.*}}, align 4
+
+// This checks the constants from inline_enum_const
+// CHECK: @alloc_[[INLINE_ENUM_HASH:[a-f0-9]{32}]] = {{.*}}, align 2
+
+// This checks the constants from {low,high}_align_const, they share the same
+// constant, but the alignment differs, so the higher one should be used
+// CHECK: [[LOW_HIGH:@alloc_[a-f0-9]{32}]] = {{.*}}, align 4
+
+#[derive(Copy, Clone)]
+// repr(i16) is required for the {low,high}_align_const test
+#[repr(i16)]
+pub enum E<A, B> {
+    A(A),
+    B(B),
+}
+
+#[no_mangle]
+pub static STATIC: E<i16, i32> = E::A(0);
+
+// CHECK-LABEL: @static_enum_const
+#[no_mangle]
+pub fn static_enum_const() -> E<i16, i32> {
+    STATIC
+}
+
+// CHECK-LABEL: @inline_enum_const
+#[no_mangle]
+pub fn inline_enum_const() -> E<i8, i16> {
+    *&E::A(0)
+}
+
+// CHECK-LABEL: @low_align_const
+#[no_mangle]
+pub fn low_align_const() -> E<i16, [i16; 3]> {
+    // Check that low_align_const and high_align_const use the same constant
+    // CHECK: memcpy.{{.+}}(ptr align 2 %_0, ptr align 2 {{.*}}[[LOW_HIGH]]{{.*}}, i{{(32|64)}} 8, i1 false)
+    *&E::A(0)
+}
+
+// CHECK-LABEL: @high_align_const
+#[no_mangle]
+pub fn high_align_const() -> E<i16, i32> {
+    // Check that low_align_const and high_align_const use the same constant
+    // CHECK: memcpy.{{.+}}(ptr align 4 %_0, ptr align 4 {{.*}}[[LOW_HIGH]]{{.*}}, i{{(32|64)}} 8, i1 false)
+    *&E::A(0)
+}
diff --git a/tests/codegen-llvm/coroutine-debug-msvc.rs b/tests/codegen-llvm/coroutine-debug-msvc.rs
new file mode 100644
index 00000000000..9e2ec3ea28a
--- /dev/null
+++ b/tests/codegen-llvm/coroutine-debug-msvc.rs
@@ -0,0 +1,60 @@
+// Verify debuginfo for coroutines:
+//  - Each variant points to the file and line of its yield point
+//  - The discriminants are marked artificial
+//  - Other fields are not marked artificial
+//
+//
+//@ compile-flags: -C debuginfo=2
+//@ only-msvc
+
+#![feature(coroutines, coroutine_trait)]
+use std::ops::Coroutine;
+
+fn coroutine_test() -> impl Coroutine<Yield = i32, Return = ()> {
+    #[coroutine]
+    || {
+        yield 0;
+        let s = String::from("foo");
+        yield 1;
+    }
+}
+
+// FIXME: No way to reliably check the filename.
+
+// CHECK-DAG:  [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "enum2$<coroutine_debug_msvc::coroutine_test::coroutine_env$0>"
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant0", scope: [[GEN]],
+// For brevity, we only check the struct name and members of the last variant.
+// CHECK-SAME: file: [[FILE:![0-9]*]], line: 15,
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant1", scope: [[GEN]],
+// CHECK-SAME: file: [[FILE]], line: 19,
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant2", scope: [[GEN]],
+// CHECK-SAME: file: [[FILE]], line: 19,
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant3", scope: [[GEN]],
+// CHECK-SAME: file: [[FILE]], line: 16,
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant4", scope: [[GEN]],
+// CHECK-SAME: file: [[FILE]], line: 18,
+// CHECK-SAME: baseType: [[VARIANT_WRAPPER:![0-9]*]]
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
+// CHECK:      [[VARIANT_WRAPPER]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Variant4", scope: [[GEN]],
+// CHECK:      !DIDerivedType(tag: DW_TAG_member, name: "value", scope: [[VARIANT_WRAPPER]], {{.*}}, baseType: [[VARIANT:![0-9]*]],
+// CHECK:      [[VARIANT]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN]],
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[VARIANT]]
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "tag", scope: [[GEN]],
+// CHECK-NOT: flags: DIFlagArtificial
+
+fn main() {
+    let _dummy = coroutine_test();
+}
diff --git a/tests/codegen-llvm/coroutine-debug.rs b/tests/codegen-llvm/coroutine-debug.rs
new file mode 100644
index 00000000000..ff62e9709b4
--- /dev/null
+++ b/tests/codegen-llvm/coroutine-debug.rs
@@ -0,0 +1,64 @@
+// Verify debuginfo for coroutines:
+//  - Each variant points to the file and line of its yield point
+//  - The discriminants are marked artificial
+//  - Other fields are not marked artificial
+//
+//
+//@ compile-flags: -C debuginfo=2
+//@ edition: 2018
+//@ ignore-msvc
+
+#![feature(coroutines, coroutine_trait)]
+use std::ops::Coroutine;
+
+fn coroutine_test() -> impl Coroutine<Yield = i32, Return = ()> {
+    #[coroutine]
+    || {
+        yield 0;
+        let s = String::from("foo");
+        yield 1;
+    }
+}
+
+// FIXME: No way to reliably check the filename.
+
+// CHECK-DAG:  [[GEN_FN:!.*]] = !DINamespace(name: "coroutine_test"
+// CHECK-DAG:  [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "{coroutine_env#0}", scope: [[GEN_FN]]
+// CHECK:      [[VARIANT:!.*]] = !DICompositeType(tag: DW_TAG_variant_part, scope: [[GEN]],
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: discriminator: [[DISC:![0-9]*]]
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "0", scope: [[VARIANT]],
+// CHECK-SAME: file: [[FILE:![0-9]*]], line: 16,
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
+// CHECK:      {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "Unresumed", scope: [[GEN]],
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "1", scope: [[VARIANT]],
+// CHECK-SAME: file: [[FILE]], line: 20,
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "2", scope: [[VARIANT]],
+// CHECK-SAME: file: [[FILE]], line: 20,
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "3", scope: [[VARIANT]],
+// CHECK-SAME: file: [[FILE]], line: 17,
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "4", scope: [[VARIANT]],
+// CHECK-SAME: file: [[FILE]], line: 19,
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
+// CHECK:      [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN]],
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[S1]]
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
+// CHECK:      [[DISC]] = !DIDerivedType(tag: DW_TAG_member, name: "__state", scope: [[GEN]],
+// CHECK-SAME: flags: DIFlagArtificial
+
+fn main() {
+    let _dummy = coroutine_test();
+}
diff --git a/tests/codegen-llvm/cross-crate-inlining/always-inline.rs b/tests/codegen-llvm/cross-crate-inlining/always-inline.rs
new file mode 100644
index 00000000000..df28b3fe197
--- /dev/null
+++ b/tests/codegen-llvm/cross-crate-inlining/always-inline.rs
@@ -0,0 +1,13 @@
+//@ compile-flags: -Copt-level=3
+//@ aux-build:always.rs
+
+#![crate_type = "lib"]
+
+extern crate always;
+
+// Check that we inline a cross-crate call, even though it isn't a leaf
+#[no_mangle]
+pub fn outer() -> String {
+    // CHECK-NOT: call {{.*}}stem_fn
+    always::stem_fn()
+}
diff --git a/tests/codegen-llvm/cross-crate-inlining/auxiliary/always.rs b/tests/codegen-llvm/cross-crate-inlining/auxiliary/always.rs
new file mode 100644
index 00000000000..6ee3f81e3c8
--- /dev/null
+++ b/tests/codegen-llvm/cross-crate-inlining/auxiliary/always.rs
@@ -0,0 +1,20 @@
+//@ compile-flags: -Copt-level=3 -Zcross-crate-inline-threshold=always
+
+#![crate_type = "lib"]
+
+// This function *looks* like it contains a call, but that call will be optimized out by MIR
+// optimizations.
+pub fn leaf_fn() -> String {
+    String::new()
+}
+
+// This function contains a call, even after MIR optimizations. It is only eligible for
+// cross-crate-inlining with "always".
+pub fn stem_fn() -> String {
+    inner()
+}
+
+#[inline(never)]
+fn inner() -> String {
+    String::from("test")
+}
diff --git a/tests/codegen-llvm/cross-crate-inlining/auxiliary/leaf.rs b/tests/codegen-llvm/cross-crate-inlining/auxiliary/leaf.rs
new file mode 100644
index 00000000000..d059a3d0a73
--- /dev/null
+++ b/tests/codegen-llvm/cross-crate-inlining/auxiliary/leaf.rs
@@ -0,0 +1,20 @@
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+
+// This function *looks* like it contains a call, but that call will be optimized out by MIR
+// optimizations.
+pub fn leaf_fn() -> String {
+    String::new()
+}
+
+// This function contains a call, even after MIR optimizations. It is only eligible for
+// cross-crate-inlining with "always".
+pub fn stem_fn() -> String {
+    inner()
+}
+
+#[inline(never)]
+fn inner() -> String {
+    String::from("test")
+}
diff --git a/tests/codegen-llvm/cross-crate-inlining/auxiliary/never.rs b/tests/codegen-llvm/cross-crate-inlining/auxiliary/never.rs
new file mode 100644
index 00000000000..55c90809ec1
--- /dev/null
+++ b/tests/codegen-llvm/cross-crate-inlining/auxiliary/never.rs
@@ -0,0 +1,20 @@
+//@ compile-flags: -Copt-level=3 -Zcross-crate-inline-threshold=never
+
+#![crate_type = "lib"]
+
+// This function *looks* like it contains a call, but that call will be optimized out by MIR
+// optimizations.
+pub fn leaf_fn() -> String {
+    String::new()
+}
+
+// This function contains a call, even after MIR optimizations. It is only eligible for
+// cross-crate-inlining with "always".
+pub fn stem_fn() -> String {
+    inner()
+}
+
+#[inline(never)]
+fn inner() -> String {
+    String::from("test")
+}
diff --git a/tests/codegen-llvm/cross-crate-inlining/leaf-inlining.rs b/tests/codegen-llvm/cross-crate-inlining/leaf-inlining.rs
new file mode 100644
index 00000000000..37132312ca9
--- /dev/null
+++ b/tests/codegen-llvm/cross-crate-inlining/leaf-inlining.rs
@@ -0,0 +1,20 @@
+//@ compile-flags: -Copt-level=3 -Zcross-crate-inline-threshold=yes
+//@ aux-build:leaf.rs
+
+#![crate_type = "lib"]
+
+extern crate leaf;
+
+// Check that we inline a leaf cross-crate call
+#[no_mangle]
+pub fn leaf_outer() -> String {
+    // CHECK-NOT: call {{.*}}leaf_fn
+    leaf::leaf_fn()
+}
+
+// Check that we do not inline a non-leaf cross-crate call
+#[no_mangle]
+pub fn stem_outer() -> String {
+    // CHECK: call {{.*}}stem_fn
+    leaf::stem_fn()
+}
diff --git a/tests/codegen-llvm/cross-crate-inlining/never-inline.rs b/tests/codegen-llvm/cross-crate-inlining/never-inline.rs
new file mode 100644
index 00000000000..759f65d9d42
--- /dev/null
+++ b/tests/codegen-llvm/cross-crate-inlining/never-inline.rs
@@ -0,0 +1,13 @@
+//@ compile-flags: -Copt-level=3
+//@ aux-build:never.rs
+
+#![crate_type = "lib"]
+
+extern crate never;
+
+// Check that we do not inline a cross-crate call, even though it is a leaf
+#[no_mangle]
+pub fn outer() -> String {
+    // CHECK: call {{.*}}leaf_fn
+    never::leaf_fn()
+}
diff --git a/tests/codegen-llvm/dealloc-no-unwind.rs b/tests/codegen-llvm/dealloc-no-unwind.rs
new file mode 100644
index 00000000000..68597817d6f
--- /dev/null
+++ b/tests/codegen-llvm/dealloc-no-unwind.rs
@@ -0,0 +1,25 @@
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+
+struct A;
+
+impl Drop for A {
+    fn drop(&mut self) {
+        extern "C" {
+            fn foo();
+        }
+        unsafe {
+            foo();
+        }
+    }
+}
+
+#[no_mangle]
+pub fn a(a: Box<i32>) {
+    // CHECK-LABEL: define{{.*}}void @a
+    // CHECK: call void @{{.*}}__rust_dealloc
+    // CHECK-NEXT: call void @foo
+    let _a = A;
+    drop(a);
+}
diff --git a/tests/codegen-llvm/debug-accessibility/crate-enum.rs b/tests/codegen-llvm/debug-accessibility/crate-enum.rs
new file mode 100644
index 00000000000..9ad5a6fd0ff
--- /dev/null
+++ b/tests/codegen-llvm/debug-accessibility/crate-enum.rs
@@ -0,0 +1,28 @@
+// ignore-tidy-linelength
+//! Checks that visibility information is present in the debuginfo for crate-visibility enums.
+
+//@ revisions: MSVC NONMSVC
+//@[MSVC] only-msvc
+//@[NONMSVC] ignore-msvc
+
+//@ compile-flags: -C debuginfo=2
+
+mod module {
+    use std::hint::black_box;
+
+    pub(crate) enum CrateFooEnum {
+        A,
+        B(u32),
+        C { x: u32 },
+    }
+
+    // NONMSVC: {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "CrateFooEnum"{{.*}}flags: DIFlagProtected{{.*}})
+    // MSVC: {{!.*}} = !DICompositeType(tag: DW_TAG_union_type, name: "enum2$<crate_enum::module::CrateFooEnum>"{{.*}}flags: DIFlagProtected{{.*}})
+    pub fn use_everything() {
+        black_box(CrateFooEnum::A);
+    }
+}
+
+fn main() {
+    module::use_everything();
+}
diff --git a/tests/codegen-llvm/debug-accessibility/crate-struct.rs b/tests/codegen-llvm/debug-accessibility/crate-struct.rs
new file mode 100644
index 00000000000..73a8ce852ed
--- /dev/null
+++ b/tests/codegen-llvm/debug-accessibility/crate-struct.rs
@@ -0,0 +1,23 @@
+//@ compile-flags: -C debuginfo=2
+
+#![allow(dead_code)]
+
+// Checks that visibility information is present in the debuginfo for crate-visibility structs.
+
+mod module {
+    use std::hint::black_box;
+
+    pub(crate) struct CrateFooStruct {
+        x: u32,
+    }
+
+    // CHECK: {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "CrateFooStruct"{{.*}}flags: DIFlagProtected{{.*}})
+
+    pub fn use_everything() {
+        black_box(CrateFooStruct { x: 2 });
+    }
+}
+
+fn main() {
+    module::use_everything();
+}
diff --git a/tests/codegen-llvm/debug-accessibility/private-enum.rs b/tests/codegen-llvm/debug-accessibility/private-enum.rs
new file mode 100644
index 00000000000..002336c03b3
--- /dev/null
+++ b/tests/codegen-llvm/debug-accessibility/private-enum.rs
@@ -0,0 +1,22 @@
+// ignore-tidy-linelength
+//! Checks that visibility information is present in the debuginfo for private enums.
+
+//@ revisions: MSVC NONMSVC
+//@[MSVC] only-msvc
+//@[NONMSVC] ignore-msvc
+//@ compile-flags: -C debuginfo=2
+
+use std::hint::black_box;
+
+enum PrivateFooEnum {
+    A,
+    B(u32),
+    C { x: u32 },
+}
+
+// NONMSVC: {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "PrivateFooEnum"{{.*}}flags: DIFlagPrivate{{.*}})
+// MSVC: {{!.*}} = !DICompositeType(tag: DW_TAG_union_type, name: "enum2$<private_enum::PrivateFooEnum>"{{.*}}flags: DIFlagPrivate{{.*}})
+
+fn main() {
+    black_box(PrivateFooEnum::A);
+}
diff --git a/tests/codegen-llvm/debug-accessibility/private-struct.rs b/tests/codegen-llvm/debug-accessibility/private-struct.rs
new file mode 100644
index 00000000000..488a680e81c
--- /dev/null
+++ b/tests/codegen-llvm/debug-accessibility/private-struct.rs
@@ -0,0 +1,17 @@
+//@ compile-flags: -C debuginfo=2
+
+#![allow(dead_code)]
+
+// Checks that visibility information is present in the debuginfo for private structs.
+
+use std::hint::black_box;
+
+struct PrivateFooStruct {
+    x: u32,
+}
+
+// CHECK: {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "PrivateFooStruct"{{.*}}flags: DIFlagPrivate{{.*}})
+
+fn main() {
+    black_box(PrivateFooStruct { x: 1 });
+}
diff --git a/tests/codegen-llvm/debug-accessibility/public-enum.rs b/tests/codegen-llvm/debug-accessibility/public-enum.rs
new file mode 100644
index 00000000000..e5cd1ab7350
--- /dev/null
+++ b/tests/codegen-llvm/debug-accessibility/public-enum.rs
@@ -0,0 +1,23 @@
+// ignore-tidy-linelength
+//! Checks that visibility information is present in the debuginfo for types and their fields.
+
+//@ revisions: MSVC NONMSVC
+//@[MSVC] only-msvc
+//@[NONMSVC] ignore-msvc
+
+//@ compile-flags: -C debuginfo=2
+
+use std::hint::black_box;
+
+pub enum PublicFooEnum {
+    A,
+    B(u32),
+    C { x: u32 },
+}
+
+// NONMSVC: {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "PublicFooEnum"{{.*}}flags: DIFlagPublic{{.*}})
+// MSVC: {{!.*}} = !DICompositeType(tag: DW_TAG_union_type, name: "enum2$<public_enum::PublicFooEnum>"{{.*}}flags: DIFlagPublic{{.*}})
+
+fn main() {
+    black_box(PublicFooEnum::A);
+}
diff --git a/tests/codegen-llvm/debug-accessibility/public-struct.rs b/tests/codegen-llvm/debug-accessibility/public-struct.rs
new file mode 100644
index 00000000000..8b2a53f993c
--- /dev/null
+++ b/tests/codegen-llvm/debug-accessibility/public-struct.rs
@@ -0,0 +1,17 @@
+//@ compile-flags: -C debuginfo=2
+
+#![allow(dead_code)]
+
+// Checks that visibility information is present in the debuginfo for public structs.
+
+use std::hint::black_box;
+
+pub struct PublicFooStruct {
+    x: u32,
+}
+
+// CHECK: {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "PublicFooStruct"{{.*}}flags: DIFlagPublic{{.*}})
+
+fn main() {
+    black_box(PublicFooStruct { x: 4 });
+}
diff --git a/tests/codegen-llvm/debug-accessibility/struct-fields.rs b/tests/codegen-llvm/debug-accessibility/struct-fields.rs
new file mode 100644
index 00000000000..f68bb3438be
--- /dev/null
+++ b/tests/codegen-llvm/debug-accessibility/struct-fields.rs
@@ -0,0 +1,30 @@
+//@ compile-flags: -C debuginfo=2
+
+#![allow(dead_code)]
+
+// Checks that visibility information is present in the debuginfo for struct fields.
+
+mod module {
+    use std::hint::black_box;
+
+    struct StructFields {
+        a: u32,
+        pub(crate) b: u32,
+        pub(super) c: u32,
+        pub d: u32,
+    }
+
+    // CHECK: [[StructFields:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "StructFields"{{.*}}flags: DIFlagPrivate{{.*}})
+    // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: [[StructFields]]{{.*}}flags: DIFlagPrivate{{.*}})
+    // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: [[StructFields]]{{.*}}flags: DIFlagProtected{{.*}})
+    // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: [[StructFields]]{{.*}}flags: DIFlagProtected{{.*}})
+    // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: [[StructFields]]{{.*}}flags: DIFlagPublic{{.*}})
+
+    pub fn use_everything() {
+        black_box(StructFields { a: 1, b: 2, c: 3, d: 4 });
+    }
+}
+
+fn main() {
+    module::use_everything();
+}
diff --git a/tests/codegen-llvm/debug-accessibility/super-enum.rs b/tests/codegen-llvm/debug-accessibility/super-enum.rs
new file mode 100644
index 00000000000..8e34d8be01f
--- /dev/null
+++ b/tests/codegen-llvm/debug-accessibility/super-enum.rs
@@ -0,0 +1,28 @@
+// ignore-tidy-linelength
+//! Checks that visibility information is present in the debuginfo for super-visibility enums.
+
+//@ revisions: MSVC NONMSVC
+//@[MSVC] only-msvc
+//@[NONMSVC] ignore-msvc
+//@ compile-flags: -C debuginfo=2
+
+mod module {
+    use std::hint::black_box;
+
+    pub(super) enum SuperFooEnum {
+        A,
+        B(u32),
+        C { x: u32 },
+    }
+
+    // NONMSVC: {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "SuperFooEnum"{{.*}}flags: DIFlagProtected{{.*}})
+    // MSVC: {{!.*}} = !DICompositeType(tag: DW_TAG_union_type, name: "enum2$<super_enum::module::SuperFooEnum>"{{.*}}flags: DIFlagProtected{{.*}})
+
+    pub fn use_everything() {
+        black_box(SuperFooEnum::A);
+    }
+}
+
+fn main() {
+    module::use_everything();
+}
diff --git a/tests/codegen-llvm/debug-accessibility/super-struct.rs b/tests/codegen-llvm/debug-accessibility/super-struct.rs
new file mode 100644
index 00000000000..63954bfb203
--- /dev/null
+++ b/tests/codegen-llvm/debug-accessibility/super-struct.rs
@@ -0,0 +1,23 @@
+//@ compile-flags: -C debuginfo=2
+
+#![allow(dead_code)]
+
+// Checks that visibility information is present in the debuginfo for super-visibility structs.
+
+mod module {
+    use std::hint::black_box;
+
+    pub(super) struct SuperFooStruct {
+        x: u32,
+    }
+
+    // CHECK: {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "SuperFooStruct"{{.*}}flags: DIFlagProtected{{.*}})
+
+    pub fn use_everything() {
+        black_box(SuperFooStruct { x: 3 });
+    }
+}
+
+fn main() {
+    module::use_everything();
+}
diff --git a/tests/codegen-llvm/debug-accessibility/tuple-fields.rs b/tests/codegen-llvm/debug-accessibility/tuple-fields.rs
new file mode 100644
index 00000000000..feec6e9eb41
--- /dev/null
+++ b/tests/codegen-llvm/debug-accessibility/tuple-fields.rs
@@ -0,0 +1,24 @@
+//@ compile-flags: -C debuginfo=2
+
+#![allow(dead_code)]
+
+// Checks that visibility information is present in the debuginfo for tuple struct fields.
+
+mod module {
+    use std::hint::black_box;
+
+    struct TupleFields(u32, pub(crate) u32, pub(super) u32, pub u32);
+
+    // CHECK: [[TupleFields:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "TupleFields"{{.*}}flags: DIFlagPrivate{{.*}})
+    // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "__0", scope: [[TupleFields]]{{.*}}flags: DIFlagPrivate{{.*}})
+    // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "__1", scope: [[TupleFields]]{{.*}}flags: DIFlagProtected{{.*}})
+    // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "__2", scope: [[TupleFields]]{{.*}}flags: DIFlagProtected{{.*}})
+    // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "__3", scope: [[TupleFields]]{{.*}}flags: DIFlagPublic{{.*}})
+    pub fn use_everything() {
+        black_box(TupleFields(1, 2, 3, 4));
+    }
+}
+
+fn main() {
+    module::use_everything();
+}
diff --git a/tests/codegen-llvm/debug-alignment.rs b/tests/codegen-llvm/debug-alignment.rs
new file mode 100644
index 00000000000..02fe05832a3
--- /dev/null
+++ b/tests/codegen-llvm/debug-alignment.rs
@@ -0,0 +1,8 @@
+// Verifies that DWARF alignment is specified properly.
+//
+//@ compile-flags: -C debuginfo=2
+#![crate_type = "lib"]
+
+// CHECK: !DIGlobalVariable
+// CHECK: align: 32
+pub static A: u32 = 1;
diff --git a/tests/codegen-llvm/debug-column-msvc.rs b/tests/codegen-llvm/debug-column-msvc.rs
new file mode 100644
index 00000000000..39f77f41329
--- /dev/null
+++ b/tests/codegen-llvm/debug-column-msvc.rs
@@ -0,0 +1,16 @@
+// Verify that no column information is emitted for MSVC targets
+//
+//@ only-msvc
+//@ compile-flags: -C debuginfo=2
+
+// CHECK-NOT: !DILexicalBlock({{.*}}column: {{.*}})
+// CHECK-NOT: !DILocation({{.*}}column: {{.*}})
+
+pub fn add(a: u32, b: u32) -> u32 {
+    a + b
+}
+
+fn main() {
+    let c = add(1, 2);
+    println!("{}", c);
+}
diff --git a/tests/codegen-llvm/debug-column.rs b/tests/codegen-llvm/debug-column.rs
new file mode 100644
index 00000000000..2aa0a8a864c
--- /dev/null
+++ b/tests/codegen-llvm/debug-column.rs
@@ -0,0 +1,25 @@
+// Verify that debuginfo column numbers are 1-based byte offsets.
+//
+//@ ignore-msvc
+//@ compile-flags: -C debuginfo=2
+
+#[rustfmt::skip]
+fn main() {
+    unsafe {
+        // Column numbers are 1-based. Regression test for #65437.
+        // CHECK: call void @giraffe(){{( #[0-9]+)?}}, !dbg [[A:!.*]]
+        giraffe();
+
+        // Column numbers use byte offests. Regression test for #67360
+        // CHECK: call void @turtle(){{( #[0-9]+)?}}, !dbg [[B:!.*]]
+/* ż */ turtle();
+
+        // CHECK: [[A]] = !DILocation(line: 11, column: 9,
+        // CHECK: [[B]] = !DILocation(line: 15, column: 10,
+    }
+}
+
+extern "C" {
+    fn giraffe();
+    fn turtle();
+}
diff --git a/tests/codegen-llvm/debug-compile-unit-path.rs b/tests/codegen-llvm/debug-compile-unit-path.rs
new file mode 100644
index 00000000000..6131d9d7351
--- /dev/null
+++ b/tests/codegen-llvm/debug-compile-unit-path.rs
@@ -0,0 +1,9 @@
+//@ compile-flags: -g --remap-path-prefix={{cwd}}=/cwd/ --remap-path-prefix={{src-base}}=/base/
+//
+//
+// Ensure that we remap the compile unit directory and that we set it to the compilers current
+// working directory and not something else.
+#![crate_type = "rlib"]
+
+// CHECK-DAG: [[FILE:![0-9]*]] = !DIFile(filename: "/base/debug-compile-unit-path.rs{{.*}}", directory: "/cwd/")
+// CHECK-DAG: {{![0-9]*}} = distinct !DICompileUnit({{.*}}file: [[FILE]]
diff --git a/tests/codegen-llvm/debug-fndef-size.rs b/tests/codegen-llvm/debug-fndef-size.rs
new file mode 100644
index 00000000000..8f716c34e7b
--- /dev/null
+++ b/tests/codegen-llvm/debug-fndef-size.rs
@@ -0,0 +1,20 @@
+// Verify that `i32::cmp` FnDef type is declared with a size of 0 and an
+// alignment of 8 bits (1 byte) in LLVM debuginfo.
+
+//@ compile-flags: -Copt-level=3 -g -Cno-prepopulate-passes
+//@ ignore-msvc the types are mangled differently
+
+use std::cmp::Ordering;
+
+fn foo<F: FnOnce(&i32, &i32) -> Ordering>(v1: i32, v2: i32, compare: F) -> Ordering {
+    compare(&v1, &v2)
+}
+
+pub fn main() {
+    foo(0, 1, i32::cmp);
+}
+
+// CHECK: %compare.dbg.spill = alloca [0 x i8], align 1
+// CHECK: dbg{{.}}declare({{(metadata )?}}ptr %compare.dbg.spill, {{(metadata )?}}![[VAR:.*]], {{(metadata )?}}!DIExpression()
+// CHECK: ![[TYPE:.*]] = !DIDerivedType(tag: DW_TAG_pointer_type, name: "fn(&i32, &i32) -> core::cmp::Ordering", baseType: !{{.*}}, align: 8, dwarfAddressSpace: {{.*}})
+// CHECK: ![[VAR]] = !DILocalVariable(name: "compare", scope: !{{.*}}, file: !{{.*}}, line: {{.*}}, type: ![[TYPE]], align: 8)
diff --git a/tests/codegen-llvm/debug-limited.rs b/tests/codegen-llvm/debug-limited.rs
new file mode 100644
index 00000000000..89a4ef0ca90
--- /dev/null
+++ b/tests/codegen-llvm/debug-limited.rs
@@ -0,0 +1,27 @@
+// Verify that the limited debuginfo option emits llvm's FullDebugInfo, but no type info.
+//
+//@ compile-flags: -C debuginfo=limited
+
+#[repr(C)]
+struct StructType {
+    a: i64,
+    b: i32,
+}
+
+extern "C" {
+    fn creator() -> *mut StructType;
+    fn save(p: *const StructType);
+}
+
+fn main() {
+    unsafe {
+        let value: &mut StructType = &mut *creator();
+        value.a = 7;
+        save(value as *const StructType)
+    }
+}
+
+// CHECK: !DICompileUnit
+// CHECK: emissionKind: FullDebug
+// CHECK: !DILocation
+// CHECK-NOT: !DIBasicType
diff --git a/tests/codegen-llvm/debug-line-directives-only.rs b/tests/codegen-llvm/debug-line-directives-only.rs
new file mode 100644
index 00000000000..709c8789bf8
--- /dev/null
+++ b/tests/codegen-llvm/debug-line-directives-only.rs
@@ -0,0 +1,27 @@
+// Verify that the only debuginfo generated are the line directives.
+//
+//@ compile-flags: -C debuginfo=line-directives-only
+
+#[repr(C)]
+struct StructType {
+    a: i64,
+    b: i32,
+}
+
+extern "C" {
+    fn creator() -> *mut StructType;
+    fn save(p: *const StructType);
+}
+
+fn main() {
+    unsafe {
+        let value: &mut StructType = &mut *creator();
+        value.a = 7;
+        save(value as *const StructType)
+    }
+}
+
+// CHECK: !DICompileUnit
+// CHECK: emissionKind: DebugDirectivesOnly
+// CHECK: !DILocation
+// CHECK-NOT: !DIBasicType
diff --git a/tests/codegen-llvm/debug-line-tables-only.rs b/tests/codegen-llvm/debug-line-tables-only.rs
new file mode 100644
index 00000000000..d50bffe6e60
--- /dev/null
+++ b/tests/codegen-llvm/debug-line-tables-only.rs
@@ -0,0 +1,27 @@
+// Verify that the only debuginfo generated are the line tables.
+//
+//@ compile-flags: -C debuginfo=line-tables-only
+
+#[repr(C)]
+struct StructType {
+    a: i64,
+    b: i32,
+}
+
+extern "C" {
+    fn creator() -> *mut StructType;
+    fn save(p: *const StructType);
+}
+
+fn main() {
+    unsafe {
+        let value: &mut StructType = &mut *creator();
+        value.a = 7;
+        save(value as *const StructType)
+    }
+}
+
+// CHECK: !DICompileUnit
+// CHECK: emissionKind: LineTablesOnly
+// CHECK: !DILocation
+// CHECK-NOT: !DIBasicType
diff --git a/tests/codegen-llvm/debug-linkage-name.rs b/tests/codegen-llvm/debug-linkage-name.rs
new file mode 100644
index 00000000000..e706040f331
--- /dev/null
+++ b/tests/codegen-llvm/debug-linkage-name.rs
@@ -0,0 +1,42 @@
+// Verifies that linkage name is omitted when it is
+// the same as variable / function name.
+//
+//@ compile-flags: -C no-prepopulate-passes -Copt-level=0
+//@ compile-flags: -C debuginfo=2 -Copt-level=0
+#![crate_type = "lib"]
+
+pub mod xyz {
+    // CHECK: !DIGlobalVariable(name: "A",
+    // CHECK:                   linkageName:
+    // CHECK-SAME:              line: 12,
+    pub static A: u32 = 1;
+
+    // CHECK: !DIGlobalVariable(name: "B",
+    // CHECK-NOT:               linkageName:
+    // CHECK-SAME:              line: 18,
+    #[no_mangle]
+    pub static B: u32 = 2;
+
+    // CHECK: !DIGlobalVariable(name: "C",
+    // CHECK-NOT:               linkageName:
+    // CHECK-SAME:              line: 24,
+    #[export_name = "C"]
+    pub static C: u32 = 2;
+
+    // CHECK: !DISubprogram(name: "e",
+    // CHECK:               linkageName:
+    // CHECK-SAME:          line: 29,
+    pub extern "C" fn e() {}
+
+    // CHECK: !DISubprogram(name: "f",
+    // CHECK-NOT:           linkageName:
+    // CHECK-SAME:          line: 35,
+    #[no_mangle]
+    pub extern "C" fn f() {}
+
+    // CHECK: !DISubprogram(name: "g",
+    // CHECK-NOT:           linkageName:
+    // CHECK-SAME:          line: 41,
+    #[export_name = "g"]
+    pub extern "C" fn g() {}
+}
diff --git a/tests/codegen-llvm/debug-vtable.rs b/tests/codegen-llvm/debug-vtable.rs
new file mode 100644
index 00000000000..8a7b1cc3c4b
--- /dev/null
+++ b/tests/codegen-llvm/debug-vtable.rs
@@ -0,0 +1,117 @@
+// ignore-tidy-linelength
+//! This test checks the debuginfo for the expected 3 vtables is generated for correct names and
+//! number of entries.
+
+//@ revisions: MSVC NONMSVC
+//@[MSVC] only-msvc
+//@[NONMSVC] ignore-msvc
+
+// Use the v0 symbol mangling scheme to codegen order independent of rustc version.
+// Unnamed items like shims are generated in lexicographical order of their symbol name and in the
+// legacy mangling scheme rustc version and generic parameters are both hashed into a single part
+// of the name, thus randomizing item order with respect to rustc version.
+
+//@ compile-flags: -Cdebuginfo=2 -Copt-level=0 -Csymbol-mangling-version=v0
+
+// Make sure that vtables don't have the unnamed_addr attribute when debuginfo is enabled.
+// This helps debuggers more reliably map from dyn pointer to concrete type.
+// CHECK: @vtable.2 = private constant [
+// CHECK: @vtable.3 = private constant <{
+// CHECK: @vtable.4 = private constant <{
+
+// NONMSVC: ![[USIZE:[0-9]+]] = !DIBasicType(name: "usize"
+// MSVC: ![[USIZE:[0-9]+]] = !DIDerivedType(tag: DW_TAG_typedef, name: "usize"
+// NONMSVC: ![[PTR:[0-9]+]] = !DIDerivedType(tag: DW_TAG_pointer_type, name: "*const ()"
+// MSVC: ![[PTR:[0-9]+]] = !DIDerivedType(tag: DW_TAG_pointer_type, name: "ptr_const$<tuple$<> >"
+
+// NONMSVC: !DIGlobalVariable(name: "<debug_vtable::Foo as debug_vtable::SomeTrait>::{vtable}"
+// MSVC: !DIGlobalVariable(name: "impl$<debug_vtable::Foo, debug_vtable::SomeTrait>::vtable$"
+
+// NONMSVC: ![[VTABLE_TY0:[0-9]+]] = !DICompositeType(tag: DW_TAG_structure_type, name: "<debug_vtable::Foo as debug_vtable::SomeTrait>::{vtable_type}", {{.*}} size: {{320|160}}, align: {{64|32}}, flags: DIFlagArtificial, {{.*}} vtableHolder: ![[FOO_TYPE:[0-9]+]],
+// MSVC: ![[VTABLE_TY0:[0-9]+]] = !DICompositeType(tag: DW_TAG_structure_type, name: "impl$<debug_vtable::Foo, debug_vtable::SomeTrait>::vtable_type$", {{.*}} size: {{320|160}}, align: {{64|32}}, flags: DIFlagArtificial, {{.*}} vtableHolder: ![[FOO_TYPE:[0-9]+]],
+// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "drop_in_place", scope: ![[VTABLE_TY0]], {{.*}} baseType: ![[PTR]], size: {{64|32}}, align: {{64|32}})
+// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "size", scope: ![[VTABLE_TY0]], {{.*}} baseType: ![[USIZE]], size: {{64|32}}, align: {{64|32}}, offset: {{64|32}})
+// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "align", scope: ![[VTABLE_TY0]], {{.*}} baseType: ![[USIZE]], size: {{64|32}}, align: {{64|32}}, offset: {{128|64}})
+// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "__method3", scope: ![[VTABLE_TY0]], {{.*}} baseType: ![[PTR]], size: {{64|32}}, align: {{64|32}}, offset: {{192|96}})
+// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "__method4", scope: ![[VTABLE_TY0]], {{.*}} baseType: ![[PTR]], size: {{64|32}}, align: {{64|32}}, offset: {{256|128}})
+// CHECK: ![[FOO_TYPE]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Foo",
+
+// NONMSVC: !DIGlobalVariable(name: "<debug_vtable::Foo as debug_vtable::SomeTraitWithGenerics<u64, i8>>::{vtable}"
+// MSVC: !DIGlobalVariable(name: "impl$<debug_vtable::Foo, debug_vtable::SomeTraitWithGenerics<u64,i8> >::vtable$"
+
+// NONMSVC: ![[VTABLE_TY1:[0-9]+]] = !DICompositeType(tag: DW_TAG_structure_type, name: "<debug_vtable::Foo as debug_vtable::SomeTraitWithGenerics<u64, i8>>::{vtable_type}", {{.*}}, size: {{256|128}}, align: {{64|32}}, flags: DIFlagArtificial, {{.*}}, vtableHolder: ![[FOO_TYPE]],
+// MSVC: ![[VTABLE_TY1:[0-9]+]] = !DICompositeType(tag: DW_TAG_structure_type, name: "impl$<debug_vtable::Foo, debug_vtable::SomeTraitWithGenerics<u64,i8> >::vtable_type$", {{.*}}, size: {{256|128}}, align: {{64|32}}, flags: DIFlagArtificial, {{.*}}, vtableHolder: ![[FOO_TYPE]],
+// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "drop_in_place", scope: ![[VTABLE_TY1]], {{.*}} baseType: ![[PTR]], size: {{64|32}}, align: {{64|32}})
+// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "size", scope: ![[VTABLE_TY1]], {{.*}} baseType: ![[USIZE]], size: {{64|32}}, align: {{64|32}}, offset: {{64|32}})
+// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "align", scope: ![[VTABLE_TY1]], {{.*}} baseType: ![[USIZE]], size: {{64|32}}, align: {{64|32}}, offset: {{128|64}})
+// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "__method3", scope: ![[VTABLE_TY1]], {{.*}} baseType: ![[PTR]], size: {{64|32}}, align: {{64|32}}, offset: {{192|96}})
+
+// NONMSVC: !DIGlobalVariable(name: "<debug_vtable::Foo as _>::{vtable}"
+// MSVC: !DIGlobalVariable(name: "impl$<debug_vtable::Foo, _>::vtable$"
+
+// NONMSVC: ![[VTABLE_TY2:[0-9]+]] = !DICompositeType(tag: DW_TAG_structure_type, name: "<debug_vtable::Foo as _>::{vtable_type}", {{.*}}, size: {{192|96}}, align: {{64|32}}, flags: DIFlagArtificial, {{.*}}, vtableHolder: ![[FOO_TYPE]],
+// MSVC: ![[VTABLE_TY2:[0-9]+]] = !DICompositeType(tag: DW_TAG_structure_type, name: "impl$<debug_vtable::Foo, _>::vtable_type$", {{.*}}, size: {{192|96}}, align: {{64|32}}, flags: DIFlagArtificial, {{.*}}, vtableHolder: ![[FOO_TYPE]],
+// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "drop_in_place", scope: ![[VTABLE_TY2]], {{.*}}, baseType: ![[PTR]], size: {{64|32}}, align: {{64|32}})
+// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "size", scope: ![[VTABLE_TY2]], {{.*}}, baseType: ![[USIZE]], size: {{64|32}}, align: {{64|32}}, offset: {{64|32}})
+// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "align", scope: ![[VTABLE_TY2]], {{.*}}, baseType: ![[USIZE]], size: {{64|32}}, align: {{64|32}}, offset: {{128|64}})
+
+// NONMSVC: !DIGlobalVariable(name: "<debug_vtable::bar::{closure_env#0} as core::ops::function::FnOnce<(core::option::Option<&dyn core::ops::function::Fn<(), Output=()>>)>>::{vtable}"
+// MSVC: !DIGlobalVariable(name: "impl$<debug_vtable::bar::closure_env$0, core::ops::function::FnOnce<tuple$<enum2$<core::option::Option<ref$<dyn$<core::ops::function::Fn<tuple$<>,assoc$<Output,tuple$<> > > > > > > > > >::vtable$"
+
+// NONMSVC: !DIGlobalVariable(name: "<debug_vtable::generic_closure::{closure_env#0}<bool> as core::ops::function::FnOnce<()>>::{vtable}"
+// MSVC: !DIGlobalVariable(name: "impl$<debug_vtable::generic_closure::closure_env$0<bool>, core::ops::function::FnOnce<tuple$<> > >::vtable$
+
+// NONMSVC: !DIGlobalVariable(name: "<debug_vtable::generic_closure::{closure_env#0}<u32> as core::ops::function::FnOnce<()>>::{vtable}"
+// MSVC: !DIGlobalVariable(name: "impl$<debug_vtable::generic_closure::closure_env$0<u32>, core::ops::function::FnOnce<tuple$<> > >::vtable$
+
+#![crate_type = "lib"]
+
+// Force emission for debuginfo for usize and *const() early..
+pub static mut XYZ: Option<(usize, *const ())> = None;
+
+pub struct Foo;
+
+pub trait SomeTrait {
+    fn method1(&self) -> u32;
+    fn method2(&self) -> u32;
+}
+
+impl SomeTrait for Foo {
+    fn method1(&self) -> u32 {
+        1
+    }
+    fn method2(&self) -> u32 {
+        2
+    }
+}
+
+pub trait SomeTraitWithGenerics<T, U> {
+    fn method1(&self) -> (T, U);
+}
+
+impl SomeTraitWithGenerics<u64, i8> for Foo {
+    fn method1(&self) -> (u64, i8) {
+        (1, 2)
+    }
+}
+
+pub fn foo(x: &Foo) -> (u32, (u64, i8), &dyn Send) {
+    let y: &dyn SomeTrait = x;
+    let z: &dyn SomeTraitWithGenerics<u64, i8> = x;
+    (y.method1(), z.method1(), x as &dyn Send)
+}
+
+// Constructing the debuginfo name for the FnOnce vtable below initially caused an ICE on MSVC
+// because the trait type contains a late bound region that needed to be erased before the type
+// layout for the niche enum `Option<&dyn Fn()>` could be computed.
+pub fn bar() -> Box<dyn FnOnce(Option<&dyn Fn()>)> {
+    Box::new(|_x: Option<&dyn Fn()>| {})
+}
+
+fn generic_closure<T: 'static>(x: T) -> Box<dyn FnOnce() -> T> {
+    Box::new(move || x)
+}
+
+pub fn instantiate_generic_closures() -> (Box<dyn FnOnce() -> u32>, Box<dyn FnOnce() -> bool>) {
+    (generic_closure(1u32), generic_closure(false))
+}
diff --git a/tests/codegen-llvm/debuginfo-constant-locals.rs b/tests/codegen-llvm/debuginfo-constant-locals.rs
new file mode 100644
index 00000000000..580c69c05a5
--- /dev/null
+++ b/tests/codegen-llvm/debuginfo-constant-locals.rs
@@ -0,0 +1,28 @@
+//@ compile-flags: -g -Copt-level=3
+
+// Check that simple constant values are preserved in debuginfo across both MIR opts and LLVM opts
+
+#![crate_type = "lib"]
+
+#[no_mangle]
+pub fn check_it() {
+    let a = 1;
+    let b = 42;
+
+    foo(a + b);
+}
+
+#[inline(never)]
+fn foo(x: i32) {
+    std::process::exit(x);
+}
+
+// CHECK-LABEL: @check_it
+// CHECK: dbg{{.}}value({{(metadata )?}}i32 1, {{(metadata )?}}![[a_metadata:[0-9]+]], {{(metadata )?}}!DIExpression()
+// CHECK: dbg{{.}}value({{(metadata )?}}i32 42, {{(metadata )?}}![[b_metadata:[0-9]+]], {{(metadata )?}}!DIExpression()
+
+// CHECK: ![[a_metadata]] = !DILocalVariable(name: "a"
+// CHECK-SAME: line: 9
+
+// CHECK: ![[b_metadata]] = !DILocalVariable(name: "b"
+// CHECK-SAME: line: 10
diff --git a/tests/codegen-llvm/debuginfo-generic-closure-env-names.rs b/tests/codegen-llvm/debuginfo-generic-closure-env-names.rs
new file mode 100644
index 00000000000..64bc58e1df7
--- /dev/null
+++ b/tests/codegen-llvm/debuginfo-generic-closure-env-names.rs
@@ -0,0 +1,90 @@
+// ignore-tidy-linelength
+//! This test checks that we get proper type names for closure environments and
+//! async-fn environments in debuginfo, especially making sure that generic arguments
+//! of the enclosing functions don't get lost.
+//!
+//! Unfortunately, the order that debuginfo gets emitted into LLVM IR becomes a bit hard
+//! to predict once async fns are involved, so DAG allows any order.
+//!
+//! Note that the test does not check async-fns when targeting MSVC because debuginfo for
+//! those does not follow the enum-fallback encoding yet and thus is incomplete.
+
+//@ revisions: MSVC NONMSVC
+//@[MSVC] only-msvc
+//@[NONMSVC] ignore-msvc
+
+// Use the v0 symbol mangling scheme to codegen order independent of rustc version.
+// Unnamed items like shims are generated in lexicographical order of their symbol name and in the
+// legacy mangling scheme rustc version and generic parameters are both hashed into a single part
+// of the name, thus randomizing item order with respect to rustc version.
+
+//@ compile-flags: -Cdebuginfo=2 -Copt-level=0 -Csymbol-mangling-version=v0
+//@ edition: 2021
+
+// non_generic_closure()
+// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{closure_env#0}", scope: ![[non_generic_closure_NAMESPACE:[0-9]+]],
+// MSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "closure_env$0", scope: ![[non_generic_closure_NAMESPACE:[0-9]+]],
+// CHECK: ![[non_generic_closure_NAMESPACE]] = !DINamespace(name: "non_generic_closure"
+
+// CHECK: ![[function_containing_closure_NAMESPACE:[0-9]+]] = !DINamespace(name: "function_containing_closure"
+// CHECK: ![[generic_async_function_NAMESPACE:[0-9]+]] = !DINamespace(name: "generic_async_function"
+// CHECK: ![[generic_async_block_NAMESPACE:[0-9]+]] = !DINamespace(name: "generic_async_block"
+
+// function_containing_closure<u32>()
+// NONMSVC-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "{closure_env#0}<u32>", scope: ![[function_containing_closure_NAMESPACE]]
+// MSVC-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "closure_env$0<u32>", scope: ![[function_containing_closure_NAMESPACE]]
+
+// generic_async_function<Foo>()
+// NONMSVC-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}<debuginfo_generic_closure_env_names::Foo>", scope: ![[generic_async_function_NAMESPACE]]
+
+// generic_async_function<u32>()
+// NONMSVC-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}<u32>", scope: ![[generic_async_function_NAMESPACE]]
+
+// generic_async_block<Foo>()
+// NONMSVC-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "{async_block_env#0}<debuginfo_generic_closure_env_names::Foo>", scope: ![[generic_async_block_NAMESPACE]]
+
+// generic_async_block<u32>()
+// NONMSVC-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "{async_block_env#0}<u32>", scope: ![[generic_async_block_NAMESPACE]]
+
+// function_containing_closure<Foo>()
+// NONMSVC-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "{closure_env#0}<debuginfo_generic_closure_env_names::Foo>", scope: ![[function_containing_closure_NAMESPACE]]
+// MSVC-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "closure_env$0<debuginfo_generic_closure_env_names::Foo>", scope: ![[function_containing_closure_NAMESPACE]]
+
+#![crate_type = "lib"]
+use std::future::Future;
+
+pub struct Foo;
+
+pub fn non_generic_closure(x: Foo) -> Box<dyn FnOnce() -> Foo> {
+    return Box::new(move || x);
+}
+
+fn function_containing_closure<T: 'static>(x: T) -> impl FnOnce() -> T {
+    // This static only exists to trigger generating the namespace debuginfo for
+    // `function_containing_closure` at a predictable, early point, which makes
+    // writing the FileCheck tests above simpler.
+    static _X: u8 = 0;
+
+    return move || x;
+}
+
+async fn generic_async_function<T: 'static>(x: T) -> T {
+    static _X: u8 = 0; // Same as above
+    x
+}
+
+fn generic_async_block<T: 'static>(x: T) -> impl Future<Output = T> {
+    static _X: u8 = 0; // Same as above
+    async move { x }
+}
+
+pub fn instantiate_generics() {
+    let _closure_u32 = function_containing_closure(7u32);
+    let _closure_foo = function_containing_closure(Foo);
+
+    let _async_fn_u32 = generic_async_function(42u32);
+    let _async_fn_foo = generic_async_function(Foo);
+
+    let _async_block_u32 = generic_async_block(64u32);
+    let _async_block_foo = generic_async_block(Foo);
+}
diff --git a/tests/codegen-llvm/debuginfo-inline-callsite-location.rs b/tests/codegen-llvm/debuginfo-inline-callsite-location.rs
new file mode 100644
index 00000000000..59ade52ad32
--- /dev/null
+++ b/tests/codegen-llvm/debuginfo-inline-callsite-location.rs
@@ -0,0 +1,27 @@
+//@ compile-flags: -g -Copt-level=3 -C panic=abort
+
+// Check that each inline call site for the same function uses the same "sub-program" so that LLVM
+// can correctly merge the debug info if it merges the inlined code (e.g., for merging of tail
+// calls to panic.
+
+// CHECK:       tail call void @{{[A-Za-z0-9_]+4core6option13unwrap_failed}}
+// CHECK-SAME:  !dbg ![[#first_dbg:]]
+// CHECK:       tail call void @{{[A-Za-z0-9_]+4core6option13unwrap_failed}}
+// CHECK-SAME:  !dbg ![[#second_dbg:]]
+
+// CHECK-DAG:   ![[#func_scope:]] = distinct !DISubprogram(name: "unwrap<i32>"
+// CHECK-DAG:   ![[#]] = !DILocalVariable(name: "self",{{( arg: 1,)?}} scope: ![[#func_scope]]
+// CHECK:       ![[#first_dbg]] = !DILocation(line: [[#]]
+// CHECK-SAME:  scope: ![[#func_scope]], inlinedAt: ![[#]])
+// CHECK:       ![[#second_dbg]] = !DILocation(line: [[#]]
+// CHECK-SAME:  scope: ![[#func_scope]], inlinedAt: ![[#]])
+
+#![crate_type = "lib"]
+
+#[no_mangle]
+extern "C" fn add_numbers(x: &Option<i32>, y: &Option<i32>) -> i32 {
+    let x1 = x.unwrap();
+    let y1 = y.unwrap();
+
+    x1 + y1
+}
diff --git a/tests/codegen-llvm/debuginfo-proc-macro/auxiliary/macro_def.rs b/tests/codegen-llvm/debuginfo-proc-macro/auxiliary/macro_def.rs
new file mode 100644
index 00000000000..c0691b23275
--- /dev/null
+++ b/tests/codegen-llvm/debuginfo-proc-macro/auxiliary/macro_def.rs
@@ -0,0 +1,7 @@
+extern crate proc_macro;
+use proc_macro::*;
+
+#[proc_macro]
+pub fn square_twice(_item: TokenStream) -> TokenStream {
+    "(square(env::vars().count() as i32), square(env::vars().count() as i32))".parse().unwrap()
+}
diff --git a/tests/codegen-llvm/debuginfo-proc-macro/mir_inlined_twice_var_locs.rs b/tests/codegen-llvm/debuginfo-proc-macro/mir_inlined_twice_var_locs.rs
new file mode 100644
index 00000000000..7530689d574
--- /dev/null
+++ b/tests/codegen-llvm/debuginfo-proc-macro/mir_inlined_twice_var_locs.rs
@@ -0,0 +1,52 @@
+//@ compile-flags: -Cdebuginfo=2 -Copt-level=0 -Zmir-enable-passes=+Inline
+// MSVC is different because of the individual allocas.
+//@ ignore-msvc
+
+//@ proc-macro: macro_def.rs
+
+// Find the variable.
+// CHECK-DAG: ![[#var_dbg:]] = !DILocalVariable(name: "n",{{( arg: 1,)?}} scope: ![[#var_scope:]]
+
+// Find both dbg_declares. These will proceed the variable metadata, of course, so we're looking
+// backwards.
+// CHECK-DAG: dbg_declare(ptr %n.dbg.spill{{[0-9]}}, ![[#var_dbg]], !DIExpression(), ![[#var_loc2:]])
+// CHECK-DAG: dbg_declare(ptr %n.dbg.spill, ![[#var_dbg]], !DIExpression(), ![[#var_loc1:]])
+
+// Find the first location definition, looking forwards again.
+// CHECK: ![[#var_loc1]] = !DILocation
+// CHECK-SAME: scope: ![[#var_scope:]], inlinedAt: ![[#var_inlinedAt1:]]
+
+// Find the first location's inlinedAt
+// NB: If we fail here it's *probably* because we failed to produce two
+// different locations and ended up reusing an earlier one.
+// CHECK: ![[#var_inlinedAt1]] = !DILocation
+// CHECK-SAME: scope: ![[var_inlinedAt1_scope:]]
+
+// Find the second location definition, still looking forwards.
+// NB: If we failed to produce two different locations, the test will
+// definitely fail by this point (if it hasn't already) because we won't
+// be able to find the same line again.
+// CHECK: ![[#var_loc2]] = !DILocation
+// CHECK-SAME: scope: ![[#var_scope]], inlinedAt: ![[#var_inlinedAt2:]]
+
+// Find the second location's inlinedAt.
+// CHECK: ![[#var_inlinedAt2]] = !DILocation
+// CHECK-SAME: scope: ![[#var_inlinedAt2_scope:]]
+
+// Finally, check that a discriminator was emitted for the second scope.
+// FIXMEkhuey ideally we would check that *either* scope has a discriminator
+// but I don't know that it's possible to check that with FileCheck.
+// CHECK: ![[#var_inlinedAt2_scope]] = !DILexicalBlockFile
+// CHECK-SAME: discriminator: [[#]]
+extern crate macro_def;
+
+use std::env;
+
+fn square(n: i32) -> i32 {
+    n * n
+}
+
+fn main() {
+    let (z1, z2) = macro_def::square_twice!();
+    println!("{z1} == {z2}");
+}
diff --git a/tests/codegen-llvm/deduced-param-attrs.rs b/tests/codegen-llvm/deduced-param-attrs.rs
new file mode 100644
index 00000000000..34504c80fad
--- /dev/null
+++ b/tests/codegen-llvm/deduced-param-attrs.rs
@@ -0,0 +1,60 @@
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+#![allow(internal_features)]
+#![feature(unsized_fn_params)]
+
+use std::cell::Cell;
+use std::hint;
+
+// Check to make sure that we can deduce the `readonly` attribute from function bodies for
+// parameters passed indirectly.
+
+pub struct BigStruct {
+    blah: [i32; 1024],
+}
+
+pub struct BigCellContainer {
+    blah: [Cell<i32>; 1024],
+}
+
+// The by-value parameter for this big struct can be marked readonly.
+//
+// CHECK: @use_big_struct_immutably({{.*}} readonly {{.*}} %big_struct)
+#[no_mangle]
+pub fn use_big_struct_immutably(big_struct: BigStruct) {
+    hint::black_box(&big_struct);
+}
+
+// The by-value parameter for this big struct can't be marked readonly, because we mutate it.
+//
+// CHECK-NOT: @use_big_struct_mutably({{.*}} readonly {{.*}} %big_struct)
+#[no_mangle]
+pub fn use_big_struct_mutably(mut big_struct: BigStruct) {
+    big_struct.blah[987] = 654;
+    hint::black_box(&big_struct);
+}
+
+// The by-value parameter for this big struct can't be marked readonly, because it contains
+// UnsafeCell.
+//
+// CHECK-NOT: @use_big_cell_container({{.*}} readonly {{.*}} %big_cell_container)
+#[no_mangle]
+pub fn use_big_cell_container(big_cell_container: BigCellContainer) {
+    hint::black_box(&big_cell_container);
+}
+
+// Make sure that we don't mistakenly mark a big struct as `readonly` when passed through a generic
+// type parameter if it contains UnsafeCell.
+//
+// CHECK-NOT: @use_something({{.*}} readonly {{.*}} %something)
+#[no_mangle]
+#[inline(never)]
+pub fn use_something<T>(something: T) {
+    hint::black_box(&something);
+}
+
+#[no_mangle]
+pub fn forward_big_cell_container(big_cell_container: BigCellContainer) {
+    use_something(big_cell_container)
+}
diff --git a/tests/codegen-llvm/default-requires-uwtable.rs b/tests/codegen-llvm/default-requires-uwtable.rs
new file mode 100644
index 00000000000..54a6e171db6
--- /dev/null
+++ b/tests/codegen-llvm/default-requires-uwtable.rs
@@ -0,0 +1,17 @@
+//@ add-core-stubs
+//@ revisions: WINDOWS_ ANDROID_
+//@ compile-flags: -C panic=abort -Copt-level=0
+//@ [WINDOWS_] compile-flags: --target=x86_64-pc-windows-msvc
+//@ [WINDOWS_] needs-llvm-components: x86
+//@ [ANDROID_] compile-flags: --target=armv7-linux-androideabi
+//@ [ANDROID_] needs-llvm-components: arm
+
+#![feature(no_core, lang_items)]
+#![crate_type = "lib"]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+// CHECK: attributes #{{.*}} uwtable
+pub fn foo() {}
diff --git a/tests/codegen-llvm/default-visibility.rs b/tests/codegen-llvm/default-visibility.rs
new file mode 100644
index 00000000000..88ff9fee254
--- /dev/null
+++ b/tests/codegen-llvm/default-visibility.rs
@@ -0,0 +1,49 @@
+// Verifies that `Session::default_visibility` is affected when using the related cmdline
+// flag.  This is a regression test for https://github.com/rust-lang/compiler-team/issues/782.  See
+// also https://github.com/rust-lang/rust/issues/73295 and
+// https://github.com/rust-lang/rust/issues/37530.
+
+//@ revisions:DEFAULT HIDDEN PROTECTED INTERPOSABLE
+//@[HIDDEN] compile-flags: -Zdefault-visibility=hidden
+//@[PROTECTED] compile-flags: -Zdefault-visibility=protected
+//@[INTERPOSABLE] compile-flags: -Zdefault-visibility=interposable
+
+// The test scenario is specifically about visibility of symbols exported out of dynamically linked
+// libraries.
+#![crate_type = "dylib"]
+
+// The test scenario needs to use a Rust-public, but non-explicitly-exported symbol
+// (e.g. the test doesn't use `#[no_mangle]`, because currently it implies that
+// the symbol should be exported;  we don't want that - we want to test the *default*
+// export setting instead).
+#[used]
+pub static tested_symbol: [u8; 6] = *b"foobar";
+
+// Exact LLVM IR differs depending on the target triple (e.g. `hidden constant`
+// vs `internal constant` vs `constant`).  Because of this, we only apply the
+// specific test expectations below to one specific target triple.  If needed,
+// additional targets can be covered by adding copies of this test file with
+// a different `only-X` directive.
+//
+//@     only-x86_64-unknown-linux-gnu
+
+// HIDDEN:       @{{.*}}default_visibility{{.*}}tested_symbol{{.*}} = hidden constant
+// PROTECTED:    @{{.*}}default_visibility{{.*}}tested_symbol{{.*}} = protected constant
+// INTERPOSABLE: @{{.*}}default_visibility{{.*}}tested_symbol{{.*}} = constant
+// DEFAULT:      @{{.*}}default_visibility{{.*}}tested_symbol{{.*}} = constant
+
+pub fn do_memcmp(left: &[u8], right: &[u8]) -> i32 {
+    left.cmp(right) as i32
+}
+
+// CHECK: define {{.*}} @{{.*}}do_memcmp{{.*}} {
+// CHECK: }
+
+// `do_memcmp` should invoke core::intrinsic::compare_bytes which emits a call
+// to the C symbol `memcmp` (at least on x86_64-unknown-linux-gnu). This symbol
+// should *not* be declared hidden or protected.
+
+// HIDDEN:       declare i32 @memcmp
+// PROTECTED:    declare i32 @memcmp
+// INTERPOSABLE: declare i32 @memcmp
+// DEFAULT:      declare i32 @memcmp
diff --git a/tests/codegen-llvm/direct-access-external-data.rs b/tests/codegen-llvm/direct-access-external-data.rs
new file mode 100644
index 00000000000..5b2ff41ef05
--- /dev/null
+++ b/tests/codegen-llvm/direct-access-external-data.rs
@@ -0,0 +1,21 @@
+//@ only-loongarch64-unknown-linux-gnu
+
+//@ revisions: DEFAULT DIRECT INDIRECT
+//@ [DEFAULT] compile-flags: -C relocation-model=static
+//@ [DIRECT] compile-flags: -C relocation-model=static -Z direct-access-external-data=yes
+//@ [INDIRECT] compile-flags: -C relocation-model=static -Z direct-access-external-data=no
+
+#![crate_type = "rlib"]
+
+// DEFAULT: @VAR = external {{.*}} global i32
+// DIRECT: @VAR = external dso_local {{.*}} global i32
+// INDIRECT: @VAR = external {{.*}} global i32
+
+extern "C" {
+    static VAR: i32;
+}
+
+#[no_mangle]
+pub fn get() -> i32 {
+    unsafe { VAR }
+}
diff --git a/tests/codegen-llvm/dllimports/auxiliary/dummy.rs b/tests/codegen-llvm/dllimports/auxiliary/dummy.rs
new file mode 100644
index 00000000000..ab3dbc6a300
--- /dev/null
+++ b/tests/codegen-llvm/dllimports/auxiliary/dummy.rs
@@ -0,0 +1,6 @@
+//@ no-prefer-dynamic
+#![crate_type = "staticlib"]
+
+// Since codegen tests don't actually perform linking, this library doesn't need to export
+// any symbols.  It's here just to satisfy the compiler looking for a .lib file when processing
+// #[link(...)] attributes in wrapper.rs.
diff --git a/tests/codegen-llvm/dllimports/auxiliary/wrapper.rs b/tests/codegen-llvm/dllimports/auxiliary/wrapper.rs
new file mode 100644
index 00000000000..00a29f7ee7e
--- /dev/null
+++ b/tests/codegen-llvm/dllimports/auxiliary/wrapper.rs
@@ -0,0 +1,14 @@
+//@ no-prefer-dynamic
+#![crate_type = "rlib"]
+
+#[link(name = "dummy", kind = "dylib")]
+extern "C" {
+    pub fn dylib_func2(x: i32) -> i32;
+    pub static dylib_global2: i32;
+}
+
+#[link(name = "dummy", kind = "static")]
+extern "C" {
+    pub fn static_func2(x: i32) -> i32;
+    pub static static_global2: i32;
+}
diff --git a/tests/codegen-llvm/dllimports/main.rs b/tests/codegen-llvm/dllimports/main.rs
new file mode 100644
index 00000000000..93d350a2238
--- /dev/null
+++ b/tests/codegen-llvm/dllimports/main.rs
@@ -0,0 +1,43 @@
+// This test is for *-windows-msvc only.
+//@ only-windows
+//@ ignore-gnu
+
+//@ aux-build:dummy.rs
+//@ aux-build:wrapper.rs
+
+extern crate wrapper;
+
+// Check that external symbols coming from foreign dylibs are adorned with 'dllimport',
+// whereas symbols coming from foreign staticlibs are not. (RFC-1717)
+
+// CHECK: @dylib_global1 = external dllimport local_unnamed_addr global i32
+// CHECK: @dylib_global2 = external dllimport local_unnamed_addr global i32
+// CHECK: @static_global1 = external local_unnamed_addr global i32
+// CHECK: @static_global2 = external local_unnamed_addr global i32
+
+// CHECK: declare dllimport noundef i32 @dylib_func1(i32 noundef)
+// CHECK: declare dllimport noundef i32 @dylib_func2(i32 noundef)
+// CHECK: declare noundef i32 @static_func1(i32 noundef)
+// CHECK: declare noundef i32 @static_func2(i32 noundef)
+
+#[link(name = "dummy", kind = "dylib")]
+extern "C" {
+    pub fn dylib_func1(x: i32) -> i32;
+    pub static dylib_global1: i32;
+}
+
+#[link(name = "dummy", kind = "static")]
+extern "C" {
+    pub fn static_func1(x: i32) -> i32;
+    pub static static_global1: i32;
+}
+
+fn main() {
+    unsafe {
+        dylib_func1(dylib_global1);
+        wrapper::dylib_func2(wrapper::dylib_global2);
+
+        static_func1(static_global1);
+        wrapper::static_func2(wrapper::static_global2);
+    }
+}
diff --git a/tests/codegen-llvm/dont_codegen_private_const_fn_only_used_in_const_eval.rs b/tests/codegen-llvm/dont_codegen_private_const_fn_only_used_in_const_eval.rs
new file mode 100644
index 00000000000..df50b4af809
--- /dev/null
+++ b/tests/codegen-llvm/dont_codegen_private_const_fn_only_used_in_const_eval.rs
@@ -0,0 +1,27 @@
+//! This test checks that we do not monomorphize functions that are only
+//! used to evaluate static items, but never used in runtime code.
+
+//@compile-flags: --crate-type=lib -Copt-level=0
+
+#![feature(generic_const_items)]
+
+const fn foo() {}
+
+pub static FOO: () = foo();
+
+// CHECK-NOT: define{{.*}}foo{{.*}}
+
+const fn bar() {}
+
+pub const BAR: () = bar();
+
+// CHECK-NOT: define{{.*}}bar{{.*}}
+
+const fn baz() {}
+
+#[rustfmt::skip]
+pub const BAZ<const C: bool>: () = if C {
+    baz()
+};
+
+// CHECK: define{{.*}}baz{{.*}}
diff --git a/tests/codegen-llvm/drop-in-place-noalias.rs b/tests/codegen-llvm/drop-in-place-noalias.rs
new file mode 100644
index 00000000000..bff2f52781f
--- /dev/null
+++ b/tests/codegen-llvm/drop-in-place-noalias.rs
@@ -0,0 +1,38 @@
+//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes
+
+// Tests that the compiler can apply `noalias` and other &mut attributes to `drop_in_place`.
+// Note that non-Unpin types should not get `noalias`, matching &mut behavior.
+
+#![crate_type = "lib"]
+
+use std::marker::PhantomPinned;
+
+// CHECK: define internal void @{{.*}}core{{.*}}ptr{{.*}}drop_in_place{{.*}}StructUnpin{{.*}}(ptr noalias noundef align 4 dereferenceable(12) %{{.+}})
+
+// CHECK: define internal void @{{.*}}core{{.*}}ptr{{.*}}drop_in_place{{.*}}StructNotUnpin{{.*}}(ptr noundef nonnull align 4 %{{.+}})
+
+pub struct StructUnpin {
+    a: i32,
+    b: i32,
+    c: i32,
+}
+
+impl Drop for StructUnpin {
+    fn drop(&mut self) {}
+}
+
+pub struct StructNotUnpin {
+    a: i32,
+    b: i32,
+    c: i32,
+    p: PhantomPinned,
+}
+
+impl Drop for StructNotUnpin {
+    fn drop(&mut self) {}
+}
+
+pub unsafe fn main(x: StructUnpin, y: StructNotUnpin) {
+    drop(x);
+    drop(y);
+}
diff --git a/tests/codegen-llvm/drop.rs b/tests/codegen-llvm/drop.rs
new file mode 100644
index 00000000000..b22a8ef27d2
--- /dev/null
+++ b/tests/codegen-llvm/drop.rs
@@ -0,0 +1,36 @@
+//@ needs-unwind - this test verifies the amount of drop calls when unwinding is used
+//@ compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+struct SomeUniqueName;
+
+impl Drop for SomeUniqueName {
+    #[inline(never)]
+    fn drop(&mut self) {}
+}
+
+#[inline(never)]
+pub fn possibly_unwinding() {}
+
+// CHECK-LABEL: @droppy
+#[no_mangle]
+pub fn droppy() {
+    // Check that there are exactly 6 drop calls. The cleanups for the unwinding should be reused,
+    // so that's one new drop call per call to possibly_unwinding(), and finally 3 drop calls for
+    // the regular function exit. We used to have problems with quadratic growths of drop calls in
+    // such functions.
+    // FIXME(eddyb) the `void @` forces a match on the instruction, instead of the
+    // comment, that's `; call core::ptr::drop_in_place::<drop::SomeUniqueName>`
+    // for the `v0` mangling, should switch to matching on that once `legacy` is gone.
+    // CHECK-COUNT-6: {{(call|invoke) void @.*}}drop_in_place{{.*}}SomeUniqueName
+    // CHECK-NOT: {{(call|invoke) void @.*}}drop_in_place{{.*}}SomeUniqueName
+    // The next line checks for the } that ends the function definition
+    // CHECK-LABEL: {{^[}]}}
+    let _s = SomeUniqueName;
+    possibly_unwinding();
+    let _s = SomeUniqueName;
+    possibly_unwinding();
+    let _s = SomeUniqueName;
+    possibly_unwinding();
+}
diff --git a/tests/codegen-llvm/dst-offset.rs b/tests/codegen-llvm/dst-offset.rs
new file mode 100644
index 00000000000..2cf5fa9fac6
--- /dev/null
+++ b/tests/codegen-llvm/dst-offset.rs
@@ -0,0 +1,84 @@
+//! This file tests that we correctly generate GEP instructions for DST
+//! field offsets.
+//@ compile-flags: -C no-prepopulate-passes -Copt-level=0
+
+#![crate_type = "lib"]
+#![feature(extern_types, sized_hierarchy)]
+
+use std::marker::PointeeSized;
+use std::ptr::addr_of;
+
+// Hack to get the correct type for usize
+// CHECK: @helper([[USIZE:i[0-9]+]] %_1)
+#[no_mangle]
+pub fn helper(_: usize) {}
+
+struct Dst<T: PointeeSized> {
+    x: u32,
+    y: u8,
+    z: T,
+}
+
+// CHECK: @dst_dyn_trait_offset(ptr align {{[0-9]+}} [[DATA_PTR:%.+]], ptr align {{[0-9]+}} [[VTABLE_PTR:%.+]])
+#[no_mangle]
+pub fn dst_dyn_trait_offset(s: &Dst<dyn Drop>) -> &dyn Drop {
+    // The alignment of dyn trait is unknown, so we compute the offset based on align from the
+    // vtable.
+
+    // CHECK: [[SIZE_PTR:%[0-9]+]] = getelementptr inbounds i8, ptr [[VTABLE_PTR]]
+    // CHECK: load [[USIZE]], ptr [[SIZE_PTR]]
+    // CHECK: [[ALIGN_PTR:%[0-9]+]] = getelementptr inbounds i8, ptr [[VTABLE_PTR]]
+    // CHECK: load [[USIZE]], ptr [[ALIGN_PTR]]
+
+    // CHECK: getelementptr inbounds i8, ptr [[DATA_PTR]]
+    // CHECK-NEXT: insertvalue
+    // CHECK-NEXT: insertvalue
+    // CHECK-NEXT: ret
+    &s.z
+}
+
+// CHECK-LABEL: @dst_slice_offset
+#[no_mangle]
+pub fn dst_slice_offset(s: &Dst<[u16]>) -> &[u16] {
+    // The alignment of [u16] is known, so we generate a GEP directly.
+
+    // CHECK: start:
+    // CHECK-NEXT: getelementptr inbounds i8, {{.+}}, [[USIZE]] 6
+    // CHECK-NEXT: insertvalue
+    // CHECK-NEXT: insertvalue
+    // CHECK-NEXT: ret
+    &s.z
+}
+
+#[repr(packed)]
+struct PackedDstSlice {
+    x: u32,
+    y: u8,
+    z: [u16],
+}
+
+// CHECK-LABEL: @packed_dst_slice_offset
+#[no_mangle]
+pub fn packed_dst_slice_offset(s: &PackedDstSlice) -> *const [u16] {
+    // The alignment of [u16] is known, so we generate a GEP directly.
+
+    // CHECK: start:
+    // CHECK-NEXT: getelementptr inbounds i8, {{.+}}, [[USIZE]] 5
+    // CHECK-NEXT: insertvalue
+    // CHECK-NEXT: insertvalue
+    // CHECK-NEXT: ret
+    addr_of!(s.z)
+}
+
+extern "C" {
+    pub type Extern;
+}
+
+// CHECK-LABEL: @dst_extern
+#[no_mangle]
+pub fn dst_extern(s: &Dst<Extern>) -> &Extern {
+    // Computing the alignment of an extern type is currently unsupported and just panics.
+
+    // CHECK: call void @{{.+}}panic
+    &s.z
+}
diff --git a/tests/codegen-llvm/dst-vtable-align-nonzero.rs b/tests/codegen-llvm/dst-vtable-align-nonzero.rs
new file mode 100644
index 00000000000..1404bd64f50
--- /dev/null
+++ b/tests/codegen-llvm/dst-vtable-align-nonzero.rs
@@ -0,0 +1,67 @@
+//@ compile-flags: -Copt-level=3 -Z merge-functions=disabled
+
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+// This test checks that we annotate alignment loads from vtables with nonzero range metadata,
+// and that this allows LLVM to eliminate redundant `align >= 1` checks.
+
+pub trait Trait {
+    fn f(&self);
+}
+
+pub struct WrapperWithAlign1<T: ?Sized> {
+    x: u8,
+    y: T,
+}
+
+pub struct WrapperWithAlign2<T: ?Sized> {
+    x: u16,
+    y: T,
+}
+
+pub struct Struct<W: ?Sized> {
+    _field: i8,
+    dst: W,
+}
+
+// CHECK-LABEL: @eliminates_runtime_check_when_align_1
+#[no_mangle]
+pub fn eliminates_runtime_check_when_align_1(
+    x: &Struct<WrapperWithAlign1<dyn Trait>>,
+) -> &WrapperWithAlign1<dyn Trait> {
+    // CHECK: load [[USIZE:i[0-9]+]], {{.+}} !range [[RANGE_META:![0-9]+]]
+    // CHECK-NOT: llvm.umax
+    // CHECK-NOT: icmp
+    // CHECK-NOT: select
+    // CHECK: ret
+    &x.dst
+}
+
+// CHECK-LABEL: @does_not_eliminate_runtime_check_when_align_2
+#[no_mangle]
+pub fn does_not_eliminate_runtime_check_when_align_2(
+    x: &Struct<WrapperWithAlign2<dyn Trait>>,
+) -> &WrapperWithAlign2<dyn Trait> {
+    // CHECK: [[X0:%[0-9]+]] = load [[USIZE]], {{.+}} !range [[RANGE_META]]
+    // CHECK: {{icmp|llvm.umax}}
+    // CHECK: ret
+    &x.dst
+}
+
+// CHECK-LABEL: @align_load_from_align_of_val
+#[no_mangle]
+pub fn align_load_from_align_of_val(x: &dyn Trait) -> usize {
+    // CHECK: {{%[0-9]+}} = load [[USIZE]], {{.+}} !range [[RANGE_META]]
+    core::mem::align_of_val(x)
+}
+
+// CHECK-LABEL: @align_load_from_vtable_align_intrinsic
+#[no_mangle]
+pub unsafe fn align_load_from_vtable_align_intrinsic(x: &dyn Trait) -> usize {
+    let (data, vtable): (*const (), *const ()) = core::mem::transmute(x);
+    // CHECK: {{%[0-9]+}} = load [[USIZE]], {{.+}} !range [[RANGE_META]]
+    core::intrinsics::vtable_align(vtable)
+}
+
+// CHECK: [[RANGE_META]] = !{[[USIZE]] 1, [[USIZE]] 0}
diff --git a/tests/codegen-llvm/dst-vtable-size-range.rs b/tests/codegen-llvm/dst-vtable-size-range.rs
new file mode 100644
index 00000000000..670f5e8d553
--- /dev/null
+++ b/tests/codegen-llvm/dst-vtable-size-range.rs
@@ -0,0 +1,35 @@
+//@ compile-flags: -Copt-level=3 -Z merge-functions=disabled
+
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+// Check that we annotate size loads from vtables with 0..(isize::MAX + 1) range metadata.
+
+pub trait Trait {
+    fn f(&self);
+}
+
+// Note that rustc uses inclusive bounds, but LLVM uses exclusive bounds for range metadata.
+// CHECK-LABEL: @generate_exclusive_bound
+#[no_mangle]
+pub fn generate_exclusive_bound() -> usize {
+    // CHECK: ret [[USIZE:i[0-9]+]] [[EXCLUSIVE_BOUND:[-0-9]+]]
+    isize::MAX as usize + 1
+}
+
+// CHECK-LABEL: @size_load_from_size_of_val
+#[no_mangle]
+pub fn size_load_from_size_of_val(x: &dyn Trait) -> usize {
+    // CHECK: {{%[0-9]+}} = load [[USIZE]], {{.+}} !range [[RANGE_META:![0-9]+]]
+    core::mem::size_of_val(x)
+}
+
+// CHECK-LABEL: @size_load_from_vtable_size_intrinsic
+#[no_mangle]
+pub unsafe fn size_load_from_vtable_size_intrinsic(x: &dyn Trait) -> usize {
+    let (data, vtable): (*const (), *const ()) = core::mem::transmute(x);
+    // CHECK: {{%[0-9]+}} = load [[USIZE]], {{.+}} !range [[RANGE_META]]
+    core::intrinsics::vtable_size(vtable)
+}
+
+// CHECK: [[RANGE_META]] = !{[[USIZE]] 0, [[USIZE]] [[EXCLUSIVE_BOUND]]}
diff --git a/tests/codegen-llvm/ehcontguard_disabled.rs b/tests/codegen-llvm/ehcontguard_disabled.rs
new file mode 100644
index 00000000000..9efb2721b3e
--- /dev/null
+++ b/tests/codegen-llvm/ehcontguard_disabled.rs
@@ -0,0 +1,9 @@
+//@ compile-flags:
+
+#![crate_type = "lib"]
+
+// A basic test function.
+pub fn test() {}
+
+// Ensure the module flag ehcontguard is not present
+// CHECK-NOT: !"ehcontguard"
diff --git a/tests/codegen-llvm/ehcontguard_enabled.rs b/tests/codegen-llvm/ehcontguard_enabled.rs
new file mode 100644
index 00000000000..ecc5512fd5d
--- /dev/null
+++ b/tests/codegen-llvm/ehcontguard_enabled.rs
@@ -0,0 +1,9 @@
+//@ compile-flags: -Z ehcont-guard
+
+#![crate_type = "lib"]
+
+// A basic test function.
+pub fn test() {}
+
+// Ensure the module flag ehcontguard=1 is present
+// CHECK: !"ehcontguard", i32 1
diff --git a/tests/codegen-llvm/emscripten-catch-unwind-js-eh.rs b/tests/codegen-llvm/emscripten-catch-unwind-js-eh.rs
new file mode 100644
index 00000000000..f43869cf218
--- /dev/null
+++ b/tests/codegen-llvm/emscripten-catch-unwind-js-eh.rs
@@ -0,0 +1,71 @@
+//@ compile-flags: -Copt-level=3 --target wasm32-unknown-emscripten
+//@ needs-llvm-components: webassembly
+
+// Emscripten has its own unique implementation of catch_unwind (in `codegen_emcc_try`),
+// make sure it generates something reasonable.
+
+#![feature(no_core, lang_items, intrinsics, rustc_attrs)]
+#![crate_type = "lib"]
+#![no_std]
+#![no_core]
+
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
+#[lang = "sized"]
+pub trait Sized: MetaSized {}
+#[lang = "freeze"]
+trait Freeze {}
+#[lang = "copy"]
+trait Copy {}
+
+impl<T> Copy for *mut T {}
+
+#[rustc_intrinsic]
+fn size_of<T>() -> usize {
+    loop {}
+}
+
+#[rustc_intrinsic]
+unsafe fn catch_unwind(
+    try_fn: fn(_: *mut u8),
+    data: *mut u8,
+    catch_fn: fn(_: *mut u8, _: *mut u8),
+) -> i32;
+
+// CHECK-LABEL: @ptr_size
+#[no_mangle]
+pub fn ptr_size() -> usize {
+    // CHECK: ret [[PTR_SIZE:.*]]
+    size_of::<*mut u8>()
+}
+
+// CHECK-LABEL: @test_catch_unwind
+#[no_mangle]
+pub unsafe fn test_catch_unwind(
+    try_fn: fn(_: *mut u8),
+    data: *mut u8,
+    catch_fn: fn(_: *mut u8, _: *mut u8),
+) -> i32 {
+    // CHECK: start:
+    // CHECK: [[ALLOCA:%.*]] = alloca
+
+    // CHECK: catch.i:
+    // CHECK: [[LANDINGPAD:%.*]] = landingpad
+    // CHECK: [[EXCEPTION:%.*]] = extractvalue {{.*}} [[LANDINGPAD]], 0
+    // CHECK: [[SELECTOR:%.*]] = extractvalue {{.*}} [[LANDINGPAD]], 1
+
+    // CHECK: [[IS_RUST_EXN:%.*]] = icmp eq {{.*}}[[SELECTOR]]
+    // CHECK: [[IS_RUST_EXN_I8:%.*]] = zext i1 [[IS_RUST_EXN]] to i8
+
+    // CHECK: store ptr [[EXCEPTION]], ptr [[ALLOCA]]
+    // CHECK: [[IS_RUST_SLOT:%.*]] = getelementptr inbounds{{( nuw)?}} i8, ptr [[ALLOCA]], [[PTR_SIZE]]
+    // CHECK: store i8 [[IS_RUST_EXN_I8]], ptr [[IS_RUST_SLOT]]
+
+    // CHECK: call void %catch_fn(ptr %data, ptr nonnull [[ALLOCA]])
+
+    catch_unwind(try_fn, data, catch_fn)
+}
diff --git a/tests/codegen-llvm/emscripten-catch-unwind-wasm-eh.rs b/tests/codegen-llvm/emscripten-catch-unwind-wasm-eh.rs
new file mode 100644
index 00000000000..b0750d52268
--- /dev/null
+++ b/tests/codegen-llvm/emscripten-catch-unwind-wasm-eh.rs
@@ -0,0 +1,69 @@
+//@ compile-flags: -Copt-level=3 --target wasm32-unknown-emscripten -Z emscripten-wasm-eh
+//@ needs-llvm-components: webassembly
+
+// Emscripten catch_unwind using wasm exceptions
+
+#![feature(no_core, lang_items, intrinsics, rustc_attrs)]
+#![crate_type = "lib"]
+#![no_std]
+#![no_core]
+
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
+#[lang = "sized"]
+pub trait Sized: MetaSized {}
+#[lang = "freeze"]
+trait Freeze {}
+#[lang = "copy"]
+trait Copy {}
+
+impl<T> Copy for *mut T {}
+
+#[rustc_intrinsic]
+fn size_of<T>() -> usize {
+    loop {}
+}
+#[rustc_intrinsic]
+unsafe fn catch_unwind(
+    try_fn: fn(_: *mut u8),
+    data: *mut u8,
+    catch_fn: fn(_: *mut u8, _: *mut u8),
+) -> i32;
+
+// CHECK-LABEL: @ptr_size
+#[no_mangle]
+pub fn ptr_size() -> usize {
+    // CHECK: ret [[PTR_SIZE:.*]]
+    size_of::<*mut u8>()
+}
+
+// CHECK-LABEL: @test_catch_unwind
+#[no_mangle]
+pub unsafe fn test_catch_unwind(
+    try_fn: fn(_: *mut u8),
+    data: *mut u8,
+    catch_fn: fn(_: *mut u8, _: *mut u8),
+) -> i32 {
+    // CHECK: start:
+    // CHECK: invoke void %try_fn(ptr %data)
+    // CHECK:         to label %__rust_try.exit unwind label %catchswitch.i
+    // CHECK:   catchswitch.i:                                    ; preds = %start
+    // CHECK:   %catchswitch1.i = catchswitch within none [label %catchpad.i] unwind to caller
+
+    // CHECK: catchpad.i:                                       ; preds = %catchswitch.i
+    // CHECK:   %catchpad2.i = catchpad within %catchswitch1.i [ptr null]
+    // CHECK:   %0 = tail call ptr @llvm.wasm.get.exception(token %catchpad2.i)
+    // CHECK:   %1 = tail call i32 @llvm.wasm.get.ehselector(token %catchpad2.i)
+    // CHECK:   call void %catch_fn(ptr %data, ptr %0) [ "funclet"(token %catchpad2.i) ]
+    // CHECK:   catchret from %catchpad2.i to label %__rust_try.exit
+
+    // CHECK: __rust_try.exit:                                  ; preds = %start, %catchpad.i
+    // CHECK:   %common.ret.op.i = phi i32 [ 0, %start ], [ 1, %catchpad.i ]
+    // CHECK:   ret i32 %common.ret.op.i
+
+    catch_unwind(try_fn, data, catch_fn)
+}
diff --git a/tests/codegen-llvm/enable-lto-unit-splitting.rs b/tests/codegen-llvm/enable-lto-unit-splitting.rs
new file mode 100644
index 00000000000..51c2671bc4e
--- /dev/null
+++ b/tests/codegen-llvm/enable-lto-unit-splitting.rs
@@ -0,0 +1,9 @@
+// Verifies that "EnableSplitLTOUnit" module flag is added.
+//
+//@ compile-flags: -Clto -Ctarget-feature=-crt-static -Zsplit-lto-unit
+
+#![crate_type = "lib"]
+
+pub fn foo() {}
+
+// CHECK: !{{[0-9]+}} = !{i32 4, !"EnableSplitLTOUnit", i32 1}
diff --git a/tests/codegen-llvm/enum/enum-aggregate.rs b/tests/codegen-llvm/enum/enum-aggregate.rs
new file mode 100644
index 00000000000..0161e5f3fa1
--- /dev/null
+++ b/tests/codegen-llvm/enum/enum-aggregate.rs
@@ -0,0 +1,126 @@
+//@ compile-flags: -Copt-level=0 -Cno-prepopulate-passes
+//@ min-llvm-version: 19
+//@ only-64bit
+
+#![crate_type = "lib"]
+
+use std::cmp::Ordering;
+use std::num::NonZero;
+use std::ptr::NonNull;
+
+#[no_mangle]
+fn make_some_bool(x: bool) -> Option<bool> {
+    // CHECK-LABEL: i8 @make_some_bool(i1 zeroext %x)
+    // CHECK-NEXT: start:
+    // CHECK-NEXT: %[[WIDER:.+]] = zext i1 %x to i8
+    // CHECK-NEXT: ret i8 %[[WIDER]]
+    Some(x)
+}
+
+#[no_mangle]
+fn make_none_bool() -> Option<bool> {
+    // CHECK-LABEL: i8 @make_none_bool()
+    // CHECK-NEXT: start:
+    // CHECK-NEXT: ret i8 2
+    None
+}
+
+#[no_mangle]
+fn make_some_ordering(x: Ordering) -> Option<Ordering> {
+    // CHECK-LABEL: i8 @make_some_ordering(i8 %x)
+    // CHECK-NEXT: start:
+    // CHECK-NEXT: ret i8 %x
+    Some(x)
+}
+
+#[no_mangle]
+fn make_some_u16(x: u16) -> Option<u16> {
+    // CHECK-LABEL: { i16, i16 } @make_some_u16(i16 %x)
+    // CHECK-NEXT: start:
+    // CHECK-NEXT: %0 = insertvalue { i16, i16 } { i16 1, i16 poison }, i16 %x, 1
+    // CHECK-NEXT: ret { i16, i16 } %0
+    Some(x)
+}
+
+#[no_mangle]
+fn make_none_u16() -> Option<u16> {
+    // CHECK-LABEL: { i16, i16 } @make_none_u16()
+    // CHECK-NEXT: start:
+    // CHECK-NEXT: ret { i16, i16 } { i16 0, i16 undef }
+    None
+}
+
+#[no_mangle]
+fn make_some_nzu32(x: NonZero<u32>) -> Option<NonZero<u32>> {
+    // CHECK-LABEL: i32 @make_some_nzu32(i32 %x)
+    // CHECK-NEXT: start:
+    // CHECK-NEXT: ret i32 %x
+    Some(x)
+}
+
+#[no_mangle]
+fn make_ok_ptr(x: NonNull<u16>) -> Result<NonNull<u16>, usize> {
+    // CHECK-LABEL: { i64, ptr } @make_ok_ptr(ptr %x)
+    // CHECK-NEXT: start:
+    // CHECK-NEXT: %0 = insertvalue { i64, ptr } { i64 0, ptr poison }, ptr %x, 1
+    // CHECK-NEXT: ret { i64, ptr } %0
+    Ok(x)
+}
+
+#[no_mangle]
+fn make_ok_int(x: usize) -> Result<usize, NonNull<u16>> {
+    // CHECK-LABEL: { i64, ptr } @make_ok_int(i64 %x)
+    // CHECK-NEXT: start:
+    // CHECK-NEXT: %[[NOPROV:.+]] = getelementptr i8, ptr null, i64 %x
+    // CHECK-NEXT: %[[R:.+]] = insertvalue { i64, ptr } { i64 0, ptr poison }, ptr %[[NOPROV]], 1
+    // CHECK-NEXT: ret { i64, ptr } %[[R]]
+    Ok(x)
+}
+
+#[no_mangle]
+fn make_some_ref(x: &u16) -> Option<&u16> {
+    // CHECK-LABEL: ptr @make_some_ref(ptr align 2 %x)
+    // CHECK-NEXT: start:
+    // CHECK-NEXT: ret ptr %x
+    Some(x)
+}
+
+#[no_mangle]
+fn make_none_ref<'a>() -> Option<&'a u16> {
+    // CHECK-LABEL: ptr @make_none_ref()
+    // CHECK-NEXT: start:
+    // CHECK-NEXT: ret ptr null
+    None
+}
+
+#[inline(never)]
+fn make_err_generic<E>(e: E) -> Result<u32, E> {
+    // CHECK-LABEL: define{{.+}}make_err_generic
+    // CHECK-NEXT: start:
+    // CHECK-NEXT: call void @llvm.trap()
+    // CHECK-NEXT: ret i32 poison
+    Err(e)
+}
+
+#[no_mangle]
+fn make_uninhabited_err_indirectly(n: Never) -> Result<u32, Never> {
+    // CHECK-LABEL: i32 @make_uninhabited_err_indirectly()
+    // CHECK-NEXT: start:
+    // CHECK-NEXT: call{{.+}}make_err_generic
+    make_err_generic(n)
+}
+
+#[no_mangle]
+fn make_fully_uninhabited_result(v: u32, n: Never) -> Result<(u32, Never), (Never, u32)> {
+    // Actually reaching this would be UB, so we don't actually build a result.
+
+    // CHECK-LABEL: { i32, i32 } @make_fully_uninhabited_result(i32 %v)
+    // CHECK-NEXT: start:
+    // CHECK-NEXT: call void @llvm.trap()
+    // CHECK-NEXT: call void @llvm.trap()
+    // CHECK-NEXT: call void @llvm.trap()
+    // CHECK-NEXT: unreachable
+    Ok((v, n))
+}
+
+enum Never {}
diff --git a/tests/codegen-llvm/enum/enum-bounds-check-derived-idx.rs b/tests/codegen-llvm/enum/enum-bounds-check-derived-idx.rs
new file mode 100644
index 00000000000..a5785f4addf
--- /dev/null
+++ b/tests/codegen-llvm/enum/enum-bounds-check-derived-idx.rs
@@ -0,0 +1,24 @@
+// This test checks an optimization that is not guaranteed to work. This test case should not block
+// a future LLVM update.
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+
+pub enum Bar {
+    A = 1,
+    B = 3,
+}
+
+// CHECK-LABEL: @lookup_inc
+#[no_mangle]
+pub fn lookup_inc(buf: &[u8; 5], f: Bar) -> u8 {
+    // CHECK-NOT: panic_bounds_check
+    buf[f as usize + 1]
+}
+
+// CHECK-LABEL: @lookup_dec
+#[no_mangle]
+pub fn lookup_dec(buf: &[u8; 5], f: Bar) -> u8 {
+    // CHECK-NOT: panic_bounds_check
+    buf[f as usize - 1]
+}
diff --git a/tests/codegen-llvm/enum/enum-bounds-check-issue-13926.rs b/tests/codegen-llvm/enum/enum-bounds-check-issue-13926.rs
new file mode 100644
index 00000000000..6e8e5035b0d
--- /dev/null
+++ b/tests/codegen-llvm/enum/enum-bounds-check-issue-13926.rs
@@ -0,0 +1,18 @@
+// This test checks an optimization that is not guaranteed to work. This test case should not block
+// a future LLVM update.
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+
+#[repr(u8)]
+pub enum Exception {
+    Low = 5,
+    High = 10,
+}
+
+// CHECK-LABEL: @access
+#[no_mangle]
+pub fn access(array: &[usize; 12], exc: Exception) -> usize {
+    // CHECK-NOT: panic_bounds_check
+    array[(exc as u8 - 4) as usize]
+}
diff --git a/tests/codegen-llvm/enum/enum-bounds-check-issue-82871.rs b/tests/codegen-llvm/enum/enum-bounds-check-issue-82871.rs
new file mode 100644
index 00000000000..3b8a146838a
--- /dev/null
+++ b/tests/codegen-llvm/enum/enum-bounds-check-issue-82871.rs
@@ -0,0 +1,18 @@
+//@ compile-flags: -C opt-level=0
+
+#![crate_type = "lib"]
+
+#[repr(C)]
+pub enum E {
+    A,
+}
+
+// CHECK-LABEL: @index
+#[no_mangle]
+pub fn index(x: &[u32; 3], ind: E) -> u32 {
+    // Canary: we should be able to optimize out the bounds check, but we need
+    // to track the range of the discriminant result in order to be able to do that.
+    // oli-obk tried to add that, but that caused miscompilations all over the place.
+    // CHECK: panic_bounds_check
+    x[ind as usize]
+}
diff --git a/tests/codegen-llvm/enum/enum-bounds-check.rs b/tests/codegen-llvm/enum/enum-bounds-check.rs
new file mode 100644
index 00000000000..5362598ca7c
--- /dev/null
+++ b/tests/codegen-llvm/enum/enum-bounds-check.rs
@@ -0,0 +1,27 @@
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+
+pub enum Foo {
+    A,
+    B,
+}
+
+// CHECK-LABEL: @lookup
+#[no_mangle]
+pub fn lookup(buf: &[u8; 2], f: Foo) -> u8 {
+    // CHECK-NOT: panic_bounds_check
+    buf[f as usize]
+}
+
+pub enum Bar {
+    A = 2,
+    B = 3,
+}
+
+// CHECK-LABEL: @lookup_unmodified
+#[no_mangle]
+pub fn lookup_unmodified(buf: &[u8; 5], f: Bar) -> u8 {
+    // CHECK-NOT: panic_bounds_check
+    buf[f as usize]
+}
diff --git a/tests/codegen-llvm/enum/enum-debug-clike.rs b/tests/codegen-llvm/enum/enum-debug-clike.rs
new file mode 100644
index 00000000000..89c803cce5e
--- /dev/null
+++ b/tests/codegen-llvm/enum/enum-debug-clike.rs
@@ -0,0 +1,28 @@
+// This tests that debug info for "c-like" enums is properly emitted.
+// This is ignored for the fallback mode on MSVC due to problems with PDB.
+
+//
+//@ ignore-msvc
+//@ ignore-wasi wasi codegens the main symbol differently
+
+//@ compile-flags: -g -C no-prepopulate-passes
+
+// CHECK-LABEL: @main
+// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_enumeration_type,{{.*}}name: "E",{{.*}}flags: DIFlagEnumClass,{{.*}}
+// CHECK: {{.*}}DIEnumerator{{.*}}name: "A",{{.*}}value: {{[0-9].*}}
+// CHECK: {{.*}}DIEnumerator{{.*}}name: "B",{{.*}}value: {{[0-9].*}}
+// CHECK: {{.*}}DIEnumerator{{.*}}name: "C",{{.*}}value: {{[0-9].*}}
+
+#![allow(dead_code)]
+#![allow(unused_variables)]
+#![allow(unused_assignments)]
+
+enum E {
+    A,
+    B,
+    C,
+}
+
+pub fn main() {
+    let e = E::C;
+}
diff --git a/tests/codegen-llvm/enum/enum-debug-niche-2.rs b/tests/codegen-llvm/enum/enum-debug-niche-2.rs
new file mode 100644
index 00000000000..80a4081f15b
--- /dev/null
+++ b/tests/codegen-llvm/enum/enum-debug-niche-2.rs
@@ -0,0 +1,47 @@
+//! This tests that optimized enum debug info accurately reflects the enum layout.
+//! This is ignored for the fallback mode on MSVC due to problems with PDB.
+//!
+//@ compile-flags: -g -C no-prepopulate-passes
+//@ ignore-msvc
+//
+// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_variant_part,{{.*}}size: 32,{{.*}}
+// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "Placeholder",{{.*}}extraData: i32 -1{{[,)].*}}
+// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "Error",{{.*}}extraData: i32 0{{[,)].*}}
+#![feature(never_type)]
+
+#[derive(Copy, Clone)]
+pub struct Entity {
+    private: std::num::NonZero<u32>,
+}
+
+#[derive(Copy, Clone, PartialEq, Eq)]
+pub struct Declaration;
+
+impl TypeFamily for Declaration {
+    type Base = Base;
+    type Placeholder = !;
+
+    fn intern_base_data(_: BaseKind<Self>) {}
+}
+
+#[derive(Copy, Clone)]
+pub struct Base;
+
+pub trait TypeFamily: Copy + 'static {
+    type Base: Copy;
+    type Placeholder: Copy;
+
+    fn intern_base_data(_: BaseKind<Self>);
+}
+
+#[derive(Copy, Clone)]
+pub enum BaseKind<F: TypeFamily> {
+    Named(Entity),
+    Placeholder(F::Placeholder),
+    Error,
+}
+
+pub fn main() {
+    let x = BaseKind::Error::<Declaration>;
+    let y = 7;
+}
diff --git a/tests/codegen-llvm/enum/enum-debug-niche.rs b/tests/codegen-llvm/enum/enum-debug-niche.rs
new file mode 100644
index 00000000000..59e8b8a78b4
--- /dev/null
+++ b/tests/codegen-llvm/enum/enum-debug-niche.rs
@@ -0,0 +1,35 @@
+// This tests that optimized enum debug info accurately reflects the enum layout.
+// This is ignored for the fallback mode on MSVC due to problems with PDB.
+
+//@ ignore-msvc
+//@ ignore-wasi wasi codegens the main symbol differently
+
+//@ compile-flags: -g -C no-prepopulate-passes
+
+// CHECK-LABEL: @main
+// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_variant_part,{{.*}}discriminator:{{.*}}
+// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "A",{{.*}}extraData:{{.*}}
+// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_structure_type,{{.*}}name: "A",{{.*}}
+// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "B",{{.*}}extraData:{{.*}}
+// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_structure_type,{{.*}}name: "B",{{.*}}
+// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "C",{{.*}}extraData:{{.*}}
+// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_structure_type,{{.*}}name: "C",{{.*}}
+// CHECK-NOT: {{.*}}DIDerivedType{{.*}}name: "D",{{.*}}extraData:{{.*}}
+// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "D",{{.*}}
+// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_structure_type,{{.*}}name: "D",{{.*}}
+// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}flags: DIFlagArtificial{{.*}}
+
+#![allow(dead_code)]
+#![allow(unused_variables)]
+#![allow(unused_assignments)]
+
+enum E {
+    A,
+    B,
+    C,
+    D(bool),
+}
+
+pub fn main() {
+    let e = E::D(true);
+}
diff --git a/tests/codegen-llvm/enum/enum-debug-tagged.rs b/tests/codegen-llvm/enum/enum-debug-tagged.rs
new file mode 100644
index 00000000000..e8f147665b0
--- /dev/null
+++ b/tests/codegen-llvm/enum/enum-debug-tagged.rs
@@ -0,0 +1,31 @@
+// This tests that debug info for tagged (ordinary) enums is properly emitted.
+// This is ignored for the fallback mode on MSVC due to problems with PDB.
+
+//@ ignore-msvc
+//@ ignore-wasi wasi codegens the main symbol differently
+
+//@ compile-flags: -g -C no-prepopulate-passes
+
+// CHECK-LABEL: @main
+// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_structure_type,{{.*}}name: "E",{{.*}}
+// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_variant_part,{{.*}}discriminator:{{.*}}
+// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "A",{{.*}}extraData:{{.*}}
+// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_structure_type,{{.*}}name: "A",{{.*}}
+// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "__0",{{.*}}
+// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "B",{{.*}}extraData:{{.*}}
+// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_structure_type,{{.*}}name: "B",{{.*}}
+// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "__0",{{.*}}
+// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}flags: DIFlagArtificial{{.*}}
+
+#![allow(dead_code)]
+#![allow(unused_variables)]
+#![allow(unused_assignments)]
+
+enum E {
+    A(u32),
+    B(u32),
+}
+
+pub fn main() {
+    let e = E::A(23);
+}
diff --git a/tests/codegen-llvm/enum/enum-discriminant-eq.rs b/tests/codegen-llvm/enum/enum-discriminant-eq.rs
new file mode 100644
index 00000000000..0494c5f551b
--- /dev/null
+++ b/tests/codegen-llvm/enum/enum-discriminant-eq.rs
@@ -0,0 +1,223 @@
+//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled
+//@ min-llvm-version: 20
+//@ only-64bit
+
+// The `derive(PartialEq)` on enums with field-less variants compares discriminants,
+// so make sure we emit that in some reasonable way.
+
+#![crate_type = "lib"]
+#![feature(ascii_char)]
+#![feature(core_intrinsics)]
+#![feature(repr128)]
+
+use std::ascii::Char as AC;
+use std::cmp::Ordering;
+use std::intrinsics::discriminant_value;
+use std::num::NonZero;
+
+// A type that's bigger than `isize`, unlike the usual cases that have small tags.
+#[repr(u128)]
+pub enum Giant {
+    Two = 2,
+    Three = 3,
+    Four = 4,
+}
+
+#[unsafe(no_mangle)]
+pub fn opt_bool_eq_discr(a: Option<bool>, b: Option<bool>) -> bool {
+    // CHECK-LABEL: @opt_bool_eq_discr(
+    // CHECK: %[[A:.+]] = icmp ne i8 %a, 2
+    // CHECK: %[[B:.+]] = icmp eq i8 %b, 2
+    // CHECK: %[[R:.+]] = xor i1 %[[A]], %[[B]]
+    // CHECK: ret i1 %[[R]]
+
+    discriminant_value(&a) == discriminant_value(&b)
+}
+
+#[unsafe(no_mangle)]
+pub fn opt_ord_eq_discr(a: Option<Ordering>, b: Option<Ordering>) -> bool {
+    // CHECK-LABEL: @opt_ord_eq_discr(
+    // CHECK: %[[A:.+]] = icmp ne i8 %a, 2
+    // CHECK: %[[B:.+]] = icmp eq i8 %b, 2
+    // CHECK: %[[R:.+]] = xor i1 %[[A]], %[[B]]
+    // CHECK: ret i1 %[[R]]
+
+    discriminant_value(&a) == discriminant_value(&b)
+}
+
+#[unsafe(no_mangle)]
+pub fn opt_nz32_eq_discr(a: Option<NonZero<u32>>, b: Option<NonZero<u32>>) -> bool {
+    // CHECK-LABEL: @opt_nz32_eq_discr(
+    // CHECK: %[[A:.+]] = icmp ne i32 %a, 0
+    // CHECK: %[[B:.+]] = icmp eq i32 %b, 0
+    // CHECK: %[[R:.+]] = xor i1 %[[A]], %[[B]]
+    // CHECK: ret i1 %[[R]]
+
+    discriminant_value(&a) == discriminant_value(&b)
+}
+
+#[unsafe(no_mangle)]
+pub fn opt_ac_eq_discr(a: Option<AC>, b: Option<AC>) -> bool {
+    // CHECK-LABEL: @opt_ac_eq_discr(
+    // CHECK: %[[A:.+]] = icmp ne i8 %a, -128
+    // CHECK: %[[B:.+]] = icmp eq i8 %b, -128
+    // CHECK: %[[R:.+]] = xor i1 %[[A]], %[[B]]
+    // CHECK: ret i1 %[[R]]
+
+    discriminant_value(&a) == discriminant_value(&b)
+}
+
+#[unsafe(no_mangle)]
+pub fn opt_giant_eq_discr(a: Option<Giant>, b: Option<Giant>) -> bool {
+    // CHECK-LABEL: @opt_giant_eq_discr(
+    // CHECK: %[[A:.+]] = icmp ne i128 %a, 1
+    // CHECK: %[[B:.+]] = icmp eq i128 %b, 1
+    // CHECK: %[[R:.+]] = xor i1 %[[A]], %[[B]]
+    // CHECK: ret i1 %[[R]]
+
+    discriminant_value(&a) == discriminant_value(&b)
+}
+
+pub enum Mid<T> {
+    Before,
+    Thing(T),
+    After,
+}
+
+#[unsafe(no_mangle)]
+pub fn mid_bool_eq_discr(a: Mid<bool>, b: Mid<bool>) -> bool {
+    // CHECK-LABEL: @mid_bool_eq_discr(
+
+    // CHECK: %[[A_REL_DISCR:.+]] = add nsw i8 %a, -2
+    // CHECK: %[[A_IS_NICHE:.+]] = icmp samesign ugt i8 %a, 1
+    // CHECK: %[[A_NOT_HOLE:.+]] = icmp ne i8 %[[A_REL_DISCR]], 1
+    // CHECK: tail call void @llvm.assume(i1 %[[A_NOT_HOLE]])
+    // CHECK: %[[A_DISCR:.+]] = select i1 %[[A_IS_NICHE]], i8 %[[A_REL_DISCR]], i8 1
+
+    // CHECK: %[[B_REL_DISCR:.+]] = add nsw i8 %b, -2
+    // CHECK: %[[B_IS_NICHE:.+]] = icmp samesign ugt i8 %b, 1
+    // CHECK: %[[B_NOT_HOLE:.+]] = icmp ne i8 %[[B_REL_DISCR]], 1
+    // CHECK: tail call void @llvm.assume(i1 %[[B_NOT_HOLE]])
+    // CHECK: %[[B_DISCR:.+]] = select i1 %[[B_IS_NICHE]], i8 %[[B_REL_DISCR]], i8 1
+
+    // CHECK: ret i1 %[[R]]
+    discriminant_value(&a) == discriminant_value(&b)
+}
+
+#[unsafe(no_mangle)]
+pub fn mid_ord_eq_discr(a: Mid<Ordering>, b: Mid<Ordering>) -> bool {
+    // CHECK-LABEL: @mid_ord_eq_discr(
+
+    // CHECK: %[[A_REL_DISCR:.+]] = add nsw i8 %a, -2
+    // CHECK: %[[A_IS_NICHE:.+]] = icmp sgt i8 %a, 1
+    // CHECK: %[[A_NOT_HOLE:.+]] = icmp ne i8 %[[A_REL_DISCR]], 1
+    // CHECK: tail call void @llvm.assume(i1 %[[A_NOT_HOLE]])
+    // CHECK: %[[A_DISCR:.+]] = select i1 %[[A_IS_NICHE]], i8 %[[A_REL_DISCR]], i8 1
+
+    // CHECK: %[[B_REL_DISCR:.+]] = add nsw i8 %b, -2
+    // CHECK: %[[B_IS_NICHE:.+]] = icmp sgt i8 %b, 1
+    // CHECK: %[[B_NOT_HOLE:.+]] = icmp ne i8 %[[B_REL_DISCR]], 1
+    // CHECK: tail call void @llvm.assume(i1 %[[B_NOT_HOLE]])
+    // CHECK: %[[B_DISCR:.+]] = select i1 %[[B_IS_NICHE]], i8 %[[B_REL_DISCR]], i8 1
+
+    // CHECK: %[[R:.+]] = icmp eq i8 %[[A_DISCR]], %[[B_DISCR]]
+    // CHECK: ret i1 %[[R]]
+    discriminant_value(&a) == discriminant_value(&b)
+}
+
+#[unsafe(no_mangle)]
+pub fn mid_nz32_eq_discr(a: Mid<NonZero<u32>>, b: Mid<NonZero<u32>>) -> bool {
+    // CHECK-LABEL: @mid_nz32_eq_discr(
+    // CHECK: %[[R:.+]] = icmp eq i32 %a.0, %b.0
+    // CHECK: ret i1 %[[R]]
+    discriminant_value(&a) == discriminant_value(&b)
+}
+
+#[unsafe(no_mangle)]
+pub fn mid_ac_eq_discr(a: Mid<AC>, b: Mid<AC>) -> bool {
+    // CHECK-LABEL: @mid_ac_eq_discr(
+
+    // CHECK: %[[A_REL_DISCR:.+]] = xor i8 %a, -128
+    // CHECK: %[[A_IS_NICHE:.+]] = icmp slt i8 %a, 0
+    // CHECK: %[[A_NOT_HOLE:.+]] = icmp ne i8 %a, -127
+    // CHECK: tail call void @llvm.assume(i1 %[[A_NOT_HOLE]])
+    // CHECK: %[[A_DISCR:.+]] = select i1 %[[A_IS_NICHE]], i8 %[[A_REL_DISCR]], i8 1
+
+    // CHECK: %[[B_REL_DISCR:.+]] = xor i8 %b, -128
+    // CHECK: %[[B_IS_NICHE:.+]] = icmp slt i8 %b, 0
+    // CHECK: %[[B_NOT_HOLE:.+]] = icmp ne i8 %b, -127
+    // CHECK: tail call void @llvm.assume(i1 %[[B_NOT_HOLE]])
+    // CHECK: %[[B_DISCR:.+]] = select i1 %[[B_IS_NICHE]], i8 %[[B_REL_DISCR]], i8 1
+
+    // CHECK: %[[R:.+]] = icmp eq i8 %[[A_DISCR]], %[[B_DISCR]]
+    // CHECK: ret i1 %[[R]]
+    discriminant_value(&a) == discriminant_value(&b)
+}
+
+// FIXME: This should be improved once our LLVM fork picks up the fix for
+// <https://github.com/llvm/llvm-project/issues/134024>
+#[unsafe(no_mangle)]
+pub fn mid_giant_eq_discr(a: Mid<Giant>, b: Mid<Giant>) -> bool {
+    // CHECK-LABEL: @mid_giant_eq_discr(
+
+    // CHECK: %[[A_TRUNC:.+]] = trunc nuw nsw i128 %a to i64
+    // CHECK: %[[A_REL_DISCR:.+]] = add nsw i64 %[[A_TRUNC]], -5
+    // CHECK: %[[A_IS_NICHE:.+]] = icmp samesign ugt i128 %a, 4
+    // CHECK: %[[A_NOT_HOLE:.+]] = icmp ne i64 %[[A_REL_DISCR]], 1
+    // CHECK: tail call void @llvm.assume(i1 %[[A_NOT_HOLE]])
+    // CHECK: %[[A_DISCR:.+]] = select i1 %[[A_IS_NICHE]], i64 %[[A_REL_DISCR]], i64 1
+
+    // CHECK: %[[B_TRUNC:.+]] = trunc nuw nsw i128 %b to i64
+    // CHECK: %[[B_REL_DISCR:.+]] = add nsw i64 %[[B_TRUNC]], -5
+    // CHECK: %[[B_IS_NICHE:.+]] = icmp samesign ugt i128 %b, 4
+    // CHECK: %[[B_NOT_HOLE:.+]] = icmp ne i64 %[[B_REL_DISCR]], 1
+    // CHECK: tail call void @llvm.assume(i1 %[[B_NOT_HOLE]])
+    // CHECK: %[[B_DISCR:.+]] = select i1 %[[B_IS_NICHE]], i64 %[[B_REL_DISCR]], i64 1
+
+    // CHECK: %[[R:.+]] = icmp eq i64 %[[A_DISCR]], %[[B_DISCR]]
+    // CHECK: ret i1 %[[R]]
+    discriminant_value(&a) == discriminant_value(&b)
+}
+
+// In niche-encoded enums, testing for the untagged variant should optimize to a
+// straight-forward comparison looking for the natural range of the payload value.
+
+#[unsafe(no_mangle)]
+pub fn mid_bool_is_thing(a: Mid<bool>) -> bool {
+    // CHECK-LABEL: @mid_bool_is_thing(
+    // CHECK: %[[R:.+]] = icmp samesign ult i8 %a, 2
+    // CHECK: ret i1 %[[R]]
+    discriminant_value(&a) == 1
+}
+
+#[unsafe(no_mangle)]
+pub fn mid_ord_is_thing(a: Mid<Ordering>) -> bool {
+    // CHECK-LABEL: @mid_ord_is_thing(
+    // CHECK: %[[R:.+]] = icmp slt i8 %a, 2
+    // CHECK: ret i1 %[[R]]
+    discriminant_value(&a) == 1
+}
+
+#[unsafe(no_mangle)]
+pub fn mid_nz32_is_thing(a: Mid<NonZero<u32>>) -> bool {
+    // CHECK-LABEL: @mid_nz32_is_thing(
+    // CHECK: %[[R:.+]] = icmp eq i32 %a.0, 1
+    // CHECK: ret i1 %[[R]]
+    discriminant_value(&a) == 1
+}
+
+#[unsafe(no_mangle)]
+pub fn mid_ac_is_thing(a: Mid<AC>) -> bool {
+    // CHECK-LABEL: @mid_ac_is_thing(
+    // CHECK: %[[R:.+]] = icmp sgt i8 %a, -1
+    // CHECK: ret i1 %[[R]]
+    discriminant_value(&a) == 1
+}
+
+#[unsafe(no_mangle)]
+pub fn mid_giant_is_thing(a: Mid<Giant>) -> bool {
+    // CHECK-LABEL: @mid_giant_is_thing(
+    // CHECK: %[[R:.+]] = icmp samesign ult i128 %a, 5
+    // CHECK: ret i1 %[[R]]
+    discriminant_value(&a) == 1
+}
diff --git a/tests/codegen-llvm/enum/enum-discriminant-value.rs b/tests/codegen-llvm/enum/enum-discriminant-value.rs
new file mode 100644
index 00000000000..d6b0c6d6c10
--- /dev/null
+++ b/tests/codegen-llvm/enum/enum-discriminant-value.rs
@@ -0,0 +1,27 @@
+// Verify that DIEnumerator uses isUnsigned flag when appropriate.
+//
+//@ compile-flags: -g -C no-prepopulate-passes
+
+#[repr(i64)]
+pub enum I64 {
+    I64Min = i64::MIN,
+    I64Max = i64::MAX,
+}
+
+#[repr(u64)]
+pub enum U64 {
+    U64Min = u64::MIN,
+    U64Max = u64::MAX,
+}
+
+fn main() {
+    let _a = I64::I64Min;
+    let _b = I64::I64Max;
+    let _c = U64::U64Min;
+    let _d = U64::U64Max;
+}
+
+// CHECK: !DIEnumerator(name: "I64Min", value: -9223372036854775808)
+// CHECK: !DIEnumerator(name: "I64Max", value: 9223372036854775807)
+// CHECK: !DIEnumerator(name: "U64Min", value: 0, isUnsigned: true)
+// CHECK: !DIEnumerator(name: "U64Max", value: 18446744073709551615, isUnsigned: true)
diff --git a/tests/codegen-llvm/enum/enum-early-otherwise-branch.rs b/tests/codegen-llvm/enum/enum-early-otherwise-branch.rs
new file mode 100644
index 00000000000..8d39d8e9b74
--- /dev/null
+++ b/tests/codegen-llvm/enum/enum-early-otherwise-branch.rs
@@ -0,0 +1,25 @@
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+
+pub enum Enum {
+    A(u32),
+    B(u32),
+    C(u32),
+}
+
+#[no_mangle]
+pub fn foo(lhs: &Enum, rhs: &Enum) -> bool {
+    // CHECK-LABEL: define{{.*}}i1 @foo(
+    // CHECK-NOT: switch
+    // CHECK-NOT: br
+    // CHECK: [[SELECT:%.*]] = select
+    // CHECK-NEXT: ret i1 [[SELECT]]
+    // CHECK-NEXT: }
+    match (lhs, rhs) {
+        (Enum::A(lhs), Enum::A(rhs)) => lhs == rhs,
+        (Enum::B(lhs), Enum::B(rhs)) => lhs == rhs,
+        (Enum::C(lhs), Enum::C(rhs)) => lhs == rhs,
+        _ => false,
+    }
+}
diff --git a/tests/codegen-llvm/enum/enum-match.rs b/tests/codegen-llvm/enum/enum-match.rs
new file mode 100644
index 00000000000..57db44ec74e
--- /dev/null
+++ b/tests/codegen-llvm/enum/enum-match.rs
@@ -0,0 +1,779 @@
+//@ compile-flags: -Copt-level=1
+//@ only-64bit
+
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+// Check each of the 3 cases for `codegen_get_discr`.
+
+// FIXME: once our min-bar LLVM has `range` attributes, update the various
+// tests here to no longer have the `range`s and `nsw`s as optional.
+
+// Case 0: One tagged variant.
+pub enum Enum0 {
+    A(bool),
+    B,
+}
+
+// CHECK-LABEL: define{{( dso_local)?}} noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match0(i8{{.+}}%0)
+// CHECK-NEXT: start:
+// CHECK-NEXT: %[[IS_B:.+]] = icmp eq i8 %0, 2
+// CHECK-NEXT: %[[TRUNC:.+]] = and i8 %0, 1
+// CHECK-NEXT: %[[R:.+]] = select i1 %[[IS_B]], i8 13, i8 %[[TRUNC]]
+// CHECK-NEXT: ret i8 %[[R]]
+#[no_mangle]
+pub fn match0(e: Enum0) -> u8 {
+    use Enum0::*;
+    match e {
+        A(b) => b as u8,
+        B => 13,
+    }
+}
+
+// Case 1: Niche values are on a boundary for `range`.
+pub enum Enum1 {
+    A(bool),
+    B,
+    C,
+}
+
+// CHECK-LABEL: define{{( dso_local)?}} noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match1(i8{{.+}}%0)
+// CHECK-NEXT: start:
+// CHECK-NEXT: %[[REL_VAR:.+]] = add{{( nsw)?}} i8 %0, -2
+// CHECK-NEXT: %[[REL_VAR_WIDE:.+]] = zext i8 %[[REL_VAR]] to i64
+// CHECK-NEXT: %[[IS_NICHE:.+]] = icmp{{( samesign)?}} ugt i8 %0, 1
+// CHECK-NEXT: %[[NICHE_DISCR:.+]] = add nuw nsw i64 %[[REL_VAR_WIDE]], 1
+// CHECK-NEXT: %[[DISCR:.+]] = select i1 %[[IS_NICHE]], i64 %[[NICHE_DISCR]], i64 0
+// CHECK-NEXT: switch i64 %[[DISCR]]
+#[no_mangle]
+pub fn match1(e: Enum1) -> u8 {
+    use Enum1::*;
+    match e {
+        A(b) => b as u8,
+        B => 13,
+        C => 100,
+    }
+}
+
+// Case 2: Special cases don't apply.
+#[rustfmt::skip]
+pub enum X {
+    _2=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, _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, _128, _129, _130, _131, _132, _133,
+    _134, _135, _136, _137, _138, _139, _140, _141,
+    _142, _143, _144, _145, _146, _147, _148, _149,
+    _150, _151, _152, _153, _154, _155, _156, _157,
+    _158, _159, _160, _161, _162, _163, _164, _165,
+    _166, _167, _168, _169, _170, _171, _172, _173,
+    _174, _175, _176, _177, _178, _179, _180, _181,
+    _182, _183, _184, _185, _186, _187, _188, _189,
+    _190, _191, _192, _193, _194, _195, _196, _197,
+    _198, _199, _200, _201, _202, _203, _204, _205,
+    _206, _207, _208, _209, _210, _211, _212, _213,
+    _214, _215, _216, _217, _218, _219, _220, _221,
+    _222, _223, _224, _225, _226, _227, _228, _229,
+    _230, _231, _232, _233, _234, _235, _236, _237,
+    _238, _239, _240, _241, _242, _243, _244, _245,
+    _246, _247, _248, _249, _250, _251, _252, _253,
+}
+
+pub enum Enum2 {
+    A(X),
+    B,
+    C,
+    D,
+    E,
+}
+
+// CHECK-LABEL: define{{( dso_local)?}} noundef{{( range\(i8 [0-9]+, -?[0-9]+\))?}} i8 @match2(i8{{.+}}%0)
+// CHECK-NEXT: start:
+// CHECK-NEXT: %[[REL_VAR:.+]] = add i8 %0, 2
+// CHECK-NEXT: %[[REL_VAR_WIDE:.+]] = zext i8 %[[REL_VAR]] to i64
+// CHECK-NEXT: %[[IS_NICHE:.+]] = icmp ult i8 %[[REL_VAR]], 4
+// CHECK-NEXT: %[[NICHE_DISCR:.+]] = add nuw nsw i64 %[[REL_VAR_WIDE]], 1
+// CHECK-NEXT: %[[DISCR:.+]] = select i1 %[[IS_NICHE]], i64 %[[NICHE_DISCR]], i64 0
+// CHECK-NEXT: switch i64 %[[DISCR]]
+#[no_mangle]
+pub fn match2(e: Enum2) -> u8 {
+    use Enum2::*;
+    match e {
+        A(b) => b as u8,
+        B => 13,
+        C => 100,
+        D => 200,
+        E => 250,
+    }
+}
+
+// And make sure it works even if the niched scalar is a pointer.
+// (For example, that we don't try to `sub` on pointers.)
+
+// CHECK-LABEL: define{{( dso_local)?}} noundef{{( range\(i16 -?[0-9]+, -?[0-9]+\))?}} i16 @match3(ptr{{.+}}%0)
+// CHECK-NEXT: start:
+// CHECK-NEXT: %[[IS_NULL:.+]] = icmp eq ptr %0, null
+// CHECK-NEXT: br i1 %[[IS_NULL]]
+#[no_mangle]
+pub fn match3(e: Option<&u8>) -> i16 {
+    match e {
+        Some(r) => *r as _,
+        None => -1,
+    }
+}
+
+// If the untagged variant is in the middle, there's an impossible value that's
+// not reflected in the `range` parameter attribute, so we assume it away.
+
+#[derive(PartialEq)]
+pub enum MiddleNiche {
+    A,
+    B,
+    C(bool),
+    D,
+    E,
+}
+
+// CHECK-LABEL: define{{( dso_local)?}} noundef{{( range\(i8 -?[0-9]+, -?[0-9]+\))?}} i8 @match4(i8{{.+}}%0)
+// CHECK-NEXT: start:
+// CHECK-NEXT: %[[REL_VAR:.+]] = add{{( nsw)?}} i8 %0, -2
+// CHECK-NEXT: %[[NOT_IMPOSSIBLE:.+]] = icmp ne i8 %[[REL_VAR]], 2
+// CHECK-NEXT: call void @llvm.assume(i1 %[[NOT_IMPOSSIBLE]])
+// CHECK-NEXT: %[[NOT_NICHE:.+]] = icmp{{( samesign)?}} ult i8 %0, 2
+// CHECK-NEXT: %[[DISCR:.+]] = select i1 %[[NOT_NICHE]], i8 2, i8 %[[REL_VAR]]
+// CHECK-NEXT: switch i8 %[[DISCR]]
+#[no_mangle]
+pub fn match4(e: MiddleNiche) -> u8 {
+    use MiddleNiche::*;
+    match e {
+        A => 13,
+        B => 100,
+        C(b) => b as u8,
+        D => 200,
+        E => 250,
+    }
+}
+
+// CHECK-LABEL: define{{.+}}i1 @match4_is_c(i8{{.+}}%e)
+// CHECK-NEXT: start
+// CHECK-NEXT: %[[NOT_IMPOSSIBLE:.+]] = icmp ne i8 %e, 4
+// CHECK-NEXT: call void @llvm.assume(i1 %[[NOT_IMPOSSIBLE]])
+// CHECK-NEXT: %[[IS_C:.+]] = icmp{{( samesign)?}} ult i8 %e, 2
+// CHECK-NEXT: ret i1 %[[IS_C]]
+#[no_mangle]
+pub fn match4_is_c(e: MiddleNiche) -> bool {
+    // Before #139098, this couldn't optimize out the `select` because it looked
+    // like it was possible for a `2` to be produced on both sides.
+
+    std::intrinsics::discriminant_value(&e) == 2
+}
+
+// You have to do something pretty obnoxious to get a variant index that doesn't
+// fit in the tag size, but it's possible
+
+pub enum Never {}
+
+pub enum HugeVariantIndex {
+    V000(Never),
+    V001(Never),
+    V002(Never),
+    V003(Never),
+    V004(Never),
+    V005(Never),
+    V006(Never),
+    V007(Never),
+    V008(Never),
+    V009(Never),
+    V010(Never),
+    V011(Never),
+    V012(Never),
+    V013(Never),
+    V014(Never),
+    V015(Never),
+    V016(Never),
+    V017(Never),
+    V018(Never),
+    V019(Never),
+    V020(Never),
+    V021(Never),
+    V022(Never),
+    V023(Never),
+    V024(Never),
+    V025(Never),
+    V026(Never),
+    V027(Never),
+    V028(Never),
+    V029(Never),
+    V030(Never),
+    V031(Never),
+    V032(Never),
+    V033(Never),
+    V034(Never),
+    V035(Never),
+    V036(Never),
+    V037(Never),
+    V038(Never),
+    V039(Never),
+    V040(Never),
+    V041(Never),
+    V042(Never),
+    V043(Never),
+    V044(Never),
+    V045(Never),
+    V046(Never),
+    V047(Never),
+    V048(Never),
+    V049(Never),
+    V050(Never),
+    V051(Never),
+    V052(Never),
+    V053(Never),
+    V054(Never),
+    V055(Never),
+    V056(Never),
+    V057(Never),
+    V058(Never),
+    V059(Never),
+    V060(Never),
+    V061(Never),
+    V062(Never),
+    V063(Never),
+    V064(Never),
+    V065(Never),
+    V066(Never),
+    V067(Never),
+    V068(Never),
+    V069(Never),
+    V070(Never),
+    V071(Never),
+    V072(Never),
+    V073(Never),
+    V074(Never),
+    V075(Never),
+    V076(Never),
+    V077(Never),
+    V078(Never),
+    V079(Never),
+    V080(Never),
+    V081(Never),
+    V082(Never),
+    V083(Never),
+    V084(Never),
+    V085(Never),
+    V086(Never),
+    V087(Never),
+    V088(Never),
+    V089(Never),
+    V090(Never),
+    V091(Never),
+    V092(Never),
+    V093(Never),
+    V094(Never),
+    V095(Never),
+    V096(Never),
+    V097(Never),
+    V098(Never),
+    V099(Never),
+    V100(Never),
+    V101(Never),
+    V102(Never),
+    V103(Never),
+    V104(Never),
+    V105(Never),
+    V106(Never),
+    V107(Never),
+    V108(Never),
+    V109(Never),
+    V110(Never),
+    V111(Never),
+    V112(Never),
+    V113(Never),
+    V114(Never),
+    V115(Never),
+    V116(Never),
+    V117(Never),
+    V118(Never),
+    V119(Never),
+    V120(Never),
+    V121(Never),
+    V122(Never),
+    V123(Never),
+    V124(Never),
+    V125(Never),
+    V126(Never),
+    V127(Never),
+    V128(Never),
+    V129(Never),
+    V130(Never),
+    V131(Never),
+    V132(Never),
+    V133(Never),
+    V134(Never),
+    V135(Never),
+    V136(Never),
+    V137(Never),
+    V138(Never),
+    V139(Never),
+    V140(Never),
+    V141(Never),
+    V142(Never),
+    V143(Never),
+    V144(Never),
+    V145(Never),
+    V146(Never),
+    V147(Never),
+    V148(Never),
+    V149(Never),
+    V150(Never),
+    V151(Never),
+    V152(Never),
+    V153(Never),
+    V154(Never),
+    V155(Never),
+    V156(Never),
+    V157(Never),
+    V158(Never),
+    V159(Never),
+    V160(Never),
+    V161(Never),
+    V162(Never),
+    V163(Never),
+    V164(Never),
+    V165(Never),
+    V166(Never),
+    V167(Never),
+    V168(Never),
+    V169(Never),
+    V170(Never),
+    V171(Never),
+    V172(Never),
+    V173(Never),
+    V174(Never),
+    V175(Never),
+    V176(Never),
+    V177(Never),
+    V178(Never),
+    V179(Never),
+    V180(Never),
+    V181(Never),
+    V182(Never),
+    V183(Never),
+    V184(Never),
+    V185(Never),
+    V186(Never),
+    V187(Never),
+    V188(Never),
+    V189(Never),
+    V190(Never),
+    V191(Never),
+    V192(Never),
+    V193(Never),
+    V194(Never),
+    V195(Never),
+    V196(Never),
+    V197(Never),
+    V198(Never),
+    V199(Never),
+    V200(Never),
+    V201(Never),
+    V202(Never),
+    V203(Never),
+    V204(Never),
+    V205(Never),
+    V206(Never),
+    V207(Never),
+    V208(Never),
+    V209(Never),
+    V210(Never),
+    V211(Never),
+    V212(Never),
+    V213(Never),
+    V214(Never),
+    V215(Never),
+    V216(Never),
+    V217(Never),
+    V218(Never),
+    V219(Never),
+    V220(Never),
+    V221(Never),
+    V222(Never),
+    V223(Never),
+    V224(Never),
+    V225(Never),
+    V226(Never),
+    V227(Never),
+    V228(Never),
+    V229(Never),
+    V230(Never),
+    V231(Never),
+    V232(Never),
+    V233(Never),
+    V234(Never),
+    V235(Never),
+    V236(Never),
+    V237(Never),
+    V238(Never),
+    V239(Never),
+    V240(Never),
+    V241(Never),
+    V242(Never),
+    V243(Never),
+    V244(Never),
+    V245(Never),
+    V246(Never),
+    V247(Never),
+    V248(Never),
+    V249(Never),
+    V250(Never),
+    V251(Never),
+    V252(Never),
+    V253(Never),
+    V254(Never),
+    V255(Never),
+    V256(Never),
+
+    Possible257,
+    Bool258(bool),
+    Possible259,
+}
+
+// CHECK-LABEL: define{{( dso_local)?}} noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match5(i8{{.+}}%0)
+// CHECK-NEXT: start:
+// CHECK-NEXT: %[[REL_VAR:.+]] = add{{( nsw)?}} i8 %0, -2
+// CHECK-NEXT: %[[REL_VAR_WIDE:.+]] = zext i8 %[[REL_VAR]] to i64
+// CHECK-NEXT: %[[IS_NICHE:.+]] = icmp{{( samesign)?}} ugt i8 %0, 1
+// CHECK-NEXT: %[[NICHE_DISCR:.+]] = add nuw nsw i64 %[[REL_VAR_WIDE]], 257
+// CHECK-NEXT: %[[NOT_IMPOSSIBLE:.+]] = icmp ne i64 %[[NICHE_DISCR]], 258
+// CHECK-NEXT: call void @llvm.assume(i1 %[[NOT_IMPOSSIBLE]])
+// CHECK-NEXT: %[[DISCR:.+]] = select i1 %[[IS_NICHE]], i64 %[[NICHE_DISCR]], i64 258
+// CHECK-NEXT: switch i64 %[[DISCR]],
+// CHECK-NEXT:   i64 257,
+// CHECK-NEXT:   i64 258,
+// CHECK-NEXT:   i64 259,
+#[no_mangle]
+pub fn match5(e: HugeVariantIndex) -> u8 {
+    use HugeVariantIndex::*;
+    match e {
+        Possible257 => 13,
+        Bool258(b) => b as u8,
+        Possible259 => 100,
+    }
+}
+
+// Make an enum where the niche tags wrap both as signed and as unsigned, to hit
+// the most-fallback case where there's just nothing smart to do.
+
+pub enum E10Through65 {
+    D10 = 10,
+    D11 = 11,
+    D12 = 12,
+    D13 = 13,
+    D14 = 14,
+    D15 = 15,
+    D16 = 16,
+    D17 = 17,
+    D18 = 18,
+    D19 = 19,
+    D20 = 20,
+    D21 = 21,
+    D22 = 22,
+    D23 = 23,
+    D24 = 24,
+    D25 = 25,
+    D26 = 26,
+    D27 = 27,
+    D28 = 28,
+    D29 = 29,
+    D30 = 30,
+    D31 = 31,
+    D32 = 32,
+    D33 = 33,
+    D34 = 34,
+    D35 = 35,
+    D36 = 36,
+    D37 = 37,
+    D38 = 38,
+    D39 = 39,
+    D40 = 40,
+    D41 = 41,
+    D42 = 42,
+    D43 = 43,
+    D44 = 44,
+    D45 = 45,
+    D46 = 46,
+    D47 = 47,
+    D48 = 48,
+    D49 = 49,
+    D50 = 50,
+    D51 = 51,
+    D52 = 52,
+    D53 = 53,
+    D54 = 54,
+    D55 = 55,
+    D56 = 56,
+    D57 = 57,
+    D58 = 58,
+    D59 = 59,
+    D60 = 60,
+    D61 = 61,
+    D62 = 62,
+    D63 = 63,
+    D64 = 64,
+    D65 = 65,
+}
+
+pub enum Tricky {
+    Untagged(E10Through65),
+    V001,
+    V002,
+    V003,
+    V004,
+    V005,
+    V006,
+    V007,
+    V008,
+    V009,
+    V010,
+    V011,
+    V012,
+    V013,
+    V014,
+    V015,
+    V016,
+    V017,
+    V018,
+    V019,
+    V020,
+    V021,
+    V022,
+    V023,
+    V024,
+    V025,
+    V026,
+    V027,
+    V028,
+    V029,
+    V030,
+    V031,
+    V032,
+    V033,
+    V034,
+    V035,
+    V036,
+    V037,
+    V038,
+    V039,
+    V040,
+    V041,
+    V042,
+    V043,
+    V044,
+    V045,
+    V046,
+    V047,
+    V048,
+    V049,
+    V050,
+    V051,
+    V052,
+    V053,
+    V054,
+    V055,
+    V056,
+    V057,
+    V058,
+    V059,
+    V060,
+    V061,
+    V062,
+    V063,
+    V064,
+    V065,
+    V066,
+    V067,
+    V068,
+    V069,
+    V070,
+    V071,
+    V072,
+    V073,
+    V074,
+    V075,
+    V076,
+    V077,
+    V078,
+    V079,
+    V080,
+    V081,
+    V082,
+    V083,
+    V084,
+    V085,
+    V086,
+    V087,
+    V088,
+    V089,
+    V090,
+    V091,
+    V092,
+    V093,
+    V094,
+    V095,
+    V096,
+    V097,
+    V098,
+    V099,
+    V100,
+    V101,
+    V102,
+    V103,
+    V104,
+    V105,
+    V106,
+    V107,
+    V108,
+    V109,
+    V110,
+    V111,
+    V112,
+    V113,
+    V114,
+    V115,
+    V116,
+    V117,
+    V118,
+    V119,
+    V120,
+    V121,
+    V122,
+    V123,
+    V124,
+    V125,
+    V126,
+    V127,
+    V128,
+    V129,
+    V130,
+    V131,
+    V132,
+    V133,
+    V134,
+    V135,
+    V136,
+    V137,
+    V138,
+    V139,
+    V140,
+    V141,
+    V142,
+    V143,
+    V144,
+    V145,
+    V146,
+    V147,
+    V148,
+    V149,
+    V150,
+    V151,
+    V152,
+    V153,
+    V154,
+    V155,
+    V156,
+    V157,
+    V158,
+    V159,
+    V160,
+    V161,
+    V162,
+    V163,
+    V164,
+    V165,
+    V166,
+    V167,
+    V168,
+    V169,
+    V170,
+    V171,
+    V172,
+    V173,
+    V174,
+    V175,
+    V176,
+    V177,
+    V178,
+    V179,
+    V180,
+    V181,
+    V182,
+    V183,
+    V184,
+    V185,
+    V186,
+    V187,
+    V188,
+    V189,
+    V190,
+    V191,
+    V192,
+    V193,
+    V194,
+    V195,
+    V196,
+    V197,
+    V198,
+    V199,
+    V200,
+}
+
+const _: () = assert!(std::intrinsics::discriminant_value(&Tricky::V100) == 100);
+
+// CHECK-LABEL: define noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @discriminant6(i8 noundef %e)
+// CHECK-NEXT: start:
+// CHECK-NEXT: %[[REL_VAR:.+]] = add i8 %e, -66
+// CHECK-NEXT: %[[IS_NICHE:.+]] = icmp ult i8 %[[REL_VAR]], -56
+// CHECK-NEXT: %[[TAGGED_DISCR:.+]] = add i8 %e, -65
+// CHECK-NEXT: %[[DISCR:.+]] = select i1 %[[IS_NICHE]], i8 %[[TAGGED_DISCR]], i8 0
+// CHECK-NEXT: ret i8 %[[DISCR]]
+#[no_mangle]
+pub fn discriminant6(e: Tricky) -> u8 {
+    std::intrinsics::discriminant_value(&e) as _
+}
+
+// Case from <https://github.com/rust-lang/rust/issues/104519>,
+// where sign-extension is important.
+
+pub enum OpenResult {
+    Ok(()),
+    Err(()),
+    TransportErr(TransportErr),
+}
+
+#[repr(i32)]
+pub enum TransportErr {
+    UnknownMethod = -2,
+}
+
+#[no_mangle]
+pub fn match7(result: OpenResult) -> u8 {
+    // CHECK-LABEL: define noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match7(i32{{.+}}%result)
+    // CHECK-NEXT: start:
+    // CHECK-NEXT: %[[NOT_OK:.+]] = icmp ne i32 %result, -1
+    // CHECK-NEXT: %[[RET:.+]] = zext i1 %[[NOT_OK]] to i8
+    // CHECK-NEXT: ret i8 %[[RET]]
+    match result {
+        OpenResult::Ok(()) => 0,
+        _ => 1,
+    }
+}
diff --git a/tests/codegen-llvm/enum/enum-two-variants-match.rs b/tests/codegen-llvm/enum/enum-two-variants-match.rs
new file mode 100644
index 00000000000..12d9edc4d62
--- /dev/null
+++ b/tests/codegen-llvm/enum/enum-two-variants-match.rs
@@ -0,0 +1,130 @@
+//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes
+//@ only-64bit (because these discriminants are isize)
+
+#![crate_type = "lib"]
+
+// This directly tests what we emit for these matches, rather than what happens
+// after optimization, so it doesn't need to worry about extra flags on the
+// instructions and is less susceptible to being broken on LLVM updates.
+
+// CHECK-LABEL: @option_match
+#[no_mangle]
+pub fn option_match(x: Option<i32>) -> u16 {
+    // CHECK-NOT: %x = alloca
+    // CHECK: %[[OUT:.+]] = alloca [2 x i8]
+    // CHECK-NOT: %x = alloca
+
+    // CHECK: %[[DISCR:.+]] = zext i32 %x.0 to i64
+    // CHECK: %[[COND:.+]] = trunc nuw i64 %[[DISCR]] to i1
+    // CHECK: br i1 %[[COND]], label %[[TRUE:[a-z0-9]+]], label %[[FALSE:[a-z0-9]+]]
+
+    // CHECK: [[TRUE]]:
+    // CHECK: store i16 13, ptr %[[OUT]]
+
+    // CHECK: [[FALSE]]:
+    // CHECK: store i16 42, ptr %[[OUT]]
+
+    // CHECK: %[[RET:.+]] = load i16, ptr %[[OUT]]
+    // CHECK: ret i16 %[[RET]]
+    match x {
+        Some(_) => 13,
+        None => 42,
+    }
+}
+
+// CHECK-LABEL: @result_match
+#[no_mangle]
+pub fn result_match(x: Result<u64, i64>) -> u16 {
+    // CHECK-NOT: %x = alloca
+    // CHECK: %[[OUT:.+]] = alloca [2 x i8]
+    // CHECK-NOT: %x = alloca
+
+    // CHECK: %[[COND:.+]] = trunc nuw i64 %x.0 to i1
+    // CHECK: br i1 %[[COND]], label %[[TRUE:[a-z0-9]+]], label %[[FALSE:[a-z0-9]+]]
+
+    // CHECK: [[TRUE]]:
+    // CHECK: store i16 13, ptr %[[OUT]]
+
+    // CHECK: [[FALSE]]:
+    // CHECK: store i16 42, ptr %[[OUT]]
+
+    // CHECK: %[[RET:.+]] = load i16, ptr %[[OUT]]
+    // CHECK: ret i16 %[[RET]]
+    match x {
+        Err(_) => 13,
+        Ok(_) => 42,
+    }
+}
+
+// CHECK-LABEL: @option_bool_match(
+#[no_mangle]
+pub fn option_bool_match(x: Option<bool>) -> char {
+    // CHECK: %[[RAW:.+]] = load i8, ptr %x
+    // CHECK: %[[IS_NONE:.+]] = icmp eq i8 %[[RAW]], 2
+    // CHECK: %[[OPT_DISCR:.+]] = select i1 %[[IS_NONE]], i64 0, i64 1
+    // CHECK: %[[OPT_DISCR_T:.+]] = trunc nuw i64 %[[OPT_DISCR]] to i1
+    // CHECK: br i1 %[[OPT_DISCR_T]], label %[[BB_SOME:.+]], label %[[BB_NONE:.+]]
+
+    // CHECK: [[BB_SOME]]:
+    // CHECK: %[[FIELD:.+]] = load i8, ptr %x
+    // CHECK: %[[FIELD_T:.+]] = trunc nuw i8 %[[FIELD]] to i1
+    // CHECK: br i1 %[[FIELD_T]]
+    match x {
+        None => 'n',
+        Some(false) => 'f',
+        Some(true) => 't',
+    }
+}
+
+use std::cmp::Ordering::{self, *};
+// CHECK-LABEL: @option_ordering_match(
+#[no_mangle]
+pub fn option_ordering_match(x: Option<Ordering>) -> char {
+    // CHECK: %[[RAW:.+]] = load i8, ptr %x
+    // CHECK: %[[IS_NONE:.+]] = icmp eq i8 %[[RAW]], 2
+    // CHECK: %[[OPT_DISCR:.+]] = select i1 %[[IS_NONE]], i64 0, i64 1
+    // CHECK: %[[OPT_DISCR_T:.+]] = trunc nuw i64 %[[OPT_DISCR]] to i1
+    // CHECK: br i1 %[[OPT_DISCR_T]], label %[[BB_SOME:.+]], label %[[BB_NONE:.+]]
+
+    // CHECK: [[BB_SOME]]:
+    // CHECK: %[[FIELD:.+]] = load i8, ptr %x
+    // CHECK: switch i8 %[[FIELD]], label %[[UNREACHABLE:.+]] [
+    // CHECK-NEXT: i8 -1, label
+    // CHECK-NEXT: i8 0, label
+    // CHECK-NEXT: i8 1, label
+    // CHECK-NEXT: ]
+
+    // CHECK: [[UNREACHABLE]]:
+    // CHECK-NEXT: unreachable
+    match x {
+        None => '?',
+        Some(Less) => '<',
+        Some(Equal) => '=',
+        Some(Greater) => '>',
+    }
+}
+
+// CHECK-LABEL: @option_nonzero_match(
+#[no_mangle]
+pub fn option_nonzero_match(x: Option<std::num::NonZero<u16>>) -> u16 {
+    // CHECK: %[[OUT:.+]] = alloca [2 x i8]
+
+    // CHECK: %[[IS_NONE:.+]] = icmp eq i16 %x, 0
+    // CHECK: %[[OPT_DISCR:.+]] = select i1 %[[IS_NONE]], i64 0, i64 1
+    // CHECK: %[[OPT_DISCR_T:.+]] = trunc nuw i64 %[[OPT_DISCR]] to i1
+    // CHECK: br i1 %[[OPT_DISCR_T]], label %[[BB_SOME:.+]], label %[[BB_NONE:.+]]
+
+    // CHECK: [[BB_SOME]]:
+    // CHECK: store i16 987, ptr %[[OUT]]
+
+    // CHECK: [[BB_NONE]]:
+    // CHECK: store i16 123, ptr %[[OUT]]
+
+    // CHECK: %[[RET:.+]] = load i16, ptr %[[OUT]]
+    // CHECK: ret i16 %[[RET]]
+
+    match x {
+        None => 123,
+        Some(_) => 987,
+    }
+}
diff --git a/tests/codegen-llvm/enum/enum-u128.rs b/tests/codegen-llvm/enum/enum-u128.rs
new file mode 100644
index 00000000000..2676669f3e3
--- /dev/null
+++ b/tests/codegen-llvm/enum/enum-u128.rs
@@ -0,0 +1,25 @@
+// This tests that debug info for "c-like" 128bit enums is properly emitted.
+// This is ignored for the fallback mode on MSVC due to problems with PDB.
+
+//
+//@ ignore-msvc
+//@ ignore-wasi wasi codegens the main symbol differently
+
+//@ compile-flags: -g -C no-prepopulate-passes
+
+// CHECK-LABEL: @main
+// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_enumeration_type,{{.*}}name: "Foo",{{.*}}flags: DIFlagEnumClass,{{.*}}
+// CHECK: {{.*}}DIEnumerator{{.*}}name: "Lo",{{.*}}value: 0,{{.*}}
+// CHECK: {{.*}}DIEnumerator{{.*}}name: "Hi",{{.*}}value: 18446744073709551616,{{.*}}
+// CHECK: {{.*}}DIEnumerator{{.*}}name: "Bar",{{.*}}value: 18446745000000000123,{{.*}}
+
+#[repr(u128)]
+pub enum Foo {
+    Lo,
+    Hi = 1 << 64,
+    Bar = 18_446_745_000_000_000_123,
+}
+
+pub fn main() {
+    let foo = Foo::Bar;
+}
diff --git a/tests/codegen-llvm/enum/unreachable_enum_default_branch.rs b/tests/codegen-llvm/enum/unreachable_enum_default_branch.rs
new file mode 100644
index 00000000000..55b165fc111
--- /dev/null
+++ b/tests/codegen-llvm/enum/unreachable_enum_default_branch.rs
@@ -0,0 +1,40 @@
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
+pub struct Int(u32);
+
+const A: Int = Int(201);
+const B: Int = Int(270);
+const C: Int = Int(153);
+
+// The code is from https://github.com/rust-lang/rust/issues/119520.
+// This code will basically turn into `matches!(x.partial_cmp(&A), Some(Greater | Equal))`.
+// The otherwise branch must be `Less`.
+// CHECK-LABEL: @implicit_match(
+// CHECK-SAME: [[TMP0:%.*]])
+// CHECK-NEXT:  start:
+// CHECK-NEXT:    [[TMP1:%.*]] = add i32 [[TMP0]], -201
+// CHECK-NEXT:    icmp ult i32 [[TMP1]], 70
+// CHECK-NEXT:    icmp eq i32 [[TMP0]], 153
+// CHECK-NEXT:    [[SPEC_SELECT:%.*]] = or i1
+// CHECK-NEXT:    ret i1 [[SPEC_SELECT]]
+#[no_mangle]
+pub fn implicit_match(x: Int) -> bool {
+    (x >= A && x <= B) || x == C
+}
+
+// The code is from https://github.com/rust-lang/rust/issues/110097.
+// We expect it to generate the same optimized code as a full match.
+// CHECK-LABEL: @if_let(
+// CHECK: start:
+// CHECK-NOT: zext
+// CHECK: select
+// CHECK-NEXT: insertvalue
+// CHECK-NEXT: insertvalue
+// CHECK-NEXT: ret
+#[no_mangle]
+pub fn if_let(val: Result<i32, ()>) -> Result<i32, ()> {
+    if let Ok(x) = val { Ok(x * 2) } else { Err(()) }
+}
diff --git a/tests/codegen-llvm/ergonomic-clones/closure.rs b/tests/codegen-llvm/ergonomic-clones/closure.rs
new file mode 100644
index 00000000000..b6fc8172641
--- /dev/null
+++ b/tests/codegen-llvm/ergonomic-clones/closure.rs
@@ -0,0 +1,55 @@
+//@ compile-flags: -C no-prepopulate-passes -Copt-level=0 -Zmir-opt-level=0
+
+#![crate_type = "lib"]
+
+#![feature(ergonomic_clones)]
+#![allow(incomplete_features)]
+
+use std::clone::UseCloned;
+
+pub fn ergonomic_clone_closure_move() -> String {
+    let s = String::from("hi");
+
+    // CHECK-NOT: ; call core::clone::impls::<impl core::clone::Clone for String>::clone
+    let cl = use || s;
+    cl()
+}
+
+#[derive(Clone)]
+struct Foo;
+
+impl UseCloned for Foo {}
+
+pub fn ergonomic_clone_closure_use_cloned() -> Foo {
+    let f = Foo;
+
+    // CHECK: ; call <closure::Foo as core::clone::Clone>::clone
+    let f1 = use || f;
+
+    // CHECK: ; call <closure::Foo as core::clone::Clone>::clone
+    let f2 = use || f;
+
+    f
+}
+
+pub fn ergonomic_clone_closure_copy() -> i32 {
+    let i = 1;
+
+    // CHECK-NOT: ; call core::clone::impls::<impl core::clone::Clone for i32>::clone
+    let i1 = use || i;
+
+    // CHECK-NOT: ; call core::clone::impls::<impl core::clone::Clone for i32>::clone
+    let i2 = use || i;
+
+    i
+}
+
+pub fn ergonomic_clone_closure_use_cloned_generics<T: UseCloned>(f: T) -> T {
+    // CHECK-NOT: ; call core::clone::impls::<impl core::clone::Clone for i32>::clone
+    let f1 = use || f;
+
+    // CHECK-NOT: ; call core::clone::impls::<impl core::clone::Clone for i32>::clone
+    let f2 = use || f;
+
+    f
+}
diff --git a/tests/codegen-llvm/error-provide.rs b/tests/codegen-llvm/error-provide.rs
new file mode 100644
index 00000000000..7f091e34359
--- /dev/null
+++ b/tests/codegen-llvm/error-provide.rs
@@ -0,0 +1,50 @@
+// Codegen test for #126242
+
+//@ compile-flags: -Copt-level=3
+#![crate_type = "lib"]
+#![feature(error_generic_member_access)]
+use std::error::Request;
+use std::fmt;
+
+#[derive(Debug)]
+struct MyBacktrace1 {}
+
+#[derive(Debug)]
+struct MyBacktrace2 {}
+
+#[derive(Debug)]
+struct MyBacktrace3 {}
+
+#[derive(Debug)]
+struct MyError {
+    backtrace1: MyBacktrace1,
+    backtrace2: MyBacktrace2,
+    backtrace3: MyBacktrace3,
+    other: MyBacktrace3,
+}
+
+impl fmt::Display for MyError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "Example Error")
+    }
+}
+
+impl std::error::Error for MyError {
+    // CHECK-LABEL: @provide
+    #[no_mangle]
+    fn provide<'a>(&'a self, request: &mut Request<'a>) {
+        // LLVM should be able to optimize multiple .provide_* calls into a switch table
+        // and eliminate redundant ones, rather than compare one-by-one.
+
+        // CHECK-NEXT: start:
+        // CHECK-NEXT: %[[SCRUTINEE:[^ ]+]] = load i128, ptr
+        // CHECK-NEXT: switch i128 %[[SCRUTINEE]], label %{{.*}} [
+        // CHECK-COUNT-3: i128 {{.*}}, label %{{.*}}
+        // CHECK-NEXT: ]
+        request
+            .provide_ref::<MyBacktrace1>(&self.backtrace1)
+            .provide_ref::<MyBacktrace3>(&self.other)
+            .provide_ref::<MyBacktrace2>(&self.backtrace2)
+            .provide_ref::<MyBacktrace3>(&self.backtrace3);
+    }
+}
diff --git a/tests/codegen-llvm/export-no-mangle.rs b/tests/codegen-llvm/export-no-mangle.rs
new file mode 100644
index 00000000000..5040684f52e
--- /dev/null
+++ b/tests/codegen-llvm/export-no-mangle.rs
@@ -0,0 +1,31 @@
+//@ compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+mod private {
+    // CHECK: @FOO =
+    #[no_mangle]
+    pub static FOO: u32 = 3;
+
+    // CHECK: @BAR =
+    #[export_name = "BAR"]
+    static BAR: u32 = 3;
+
+    // CHECK: void @a()
+    #[no_mangle]
+    pub extern "C" fn a() {}
+
+    // CHECK: void @b()
+    #[export_name = "b"]
+    extern "C" fn b() {}
+
+    // CHECK: void @c()
+    #[export_name = "c"]
+    #[inline]
+    extern "C" fn c() {}
+
+    // CHECK: void @d()
+    #[export_name = "d"]
+    #[inline(always)]
+    extern "C" fn d() {}
+}
diff --git a/tests/codegen-llvm/external-no-mangle-fns.rs b/tests/codegen-llvm/external-no-mangle-fns.rs
new file mode 100644
index 00000000000..35ab0fd7909
--- /dev/null
+++ b/tests/codegen-llvm/external-no-mangle-fns.rs
@@ -0,0 +1,75 @@
+//@ compile-flags: -C no-prepopulate-passes
+// `#[no_mangle]`d functions always have external linkage, i.e., no `internal` in their `define`s
+
+#![crate_type = "lib"]
+#![no_std]
+
+// CHECK: define{{( dso_local)?}} void @a()
+#[no_mangle]
+fn a() {}
+
+// CHECK: define{{( dso_local)?}} void @b()
+#[no_mangle]
+pub fn b() {}
+
+mod private {
+    // CHECK: define{{( dso_local)?}} void @c()
+    #[no_mangle]
+    fn c() {}
+
+    // CHECK: define{{( dso_local)?}} void @d()
+    #[no_mangle]
+    pub fn d() {}
+}
+
+const HIDDEN: () = {
+    // CHECK: define{{( dso_local)?}} void @e()
+    #[no_mangle]
+    fn e() {}
+
+    // CHECK: define{{( dso_local)?}} void @f()
+    #[no_mangle]
+    pub fn f() {}
+};
+
+// The surrounding item should not accidentally become external
+// CHECK-LABEL: ; external_no_mangle_fns::x
+// CHECK-NEXT: ; Function Attrs:
+// CHECK-NEXT: define internal
+#[inline(never)]
+fn x() {
+    // CHECK: define{{( dso_local)?}} void @g()
+    #[no_mangle]
+    fn g() {
+        x();
+    }
+
+    // CHECK: define{{( dso_local)?}} void @h()
+    #[no_mangle]
+    pub fn h() {}
+
+    // side effect to keep `x` around
+    unsafe {
+        core::ptr::read_volatile(&42);
+    }
+}
+
+// CHECK: define{{( dso_local)?}} void @i()
+#[no_mangle]
+#[inline]
+fn i() {}
+
+// CHECK: define{{( dso_local)?}} void @j()
+#[no_mangle]
+#[inline]
+pub fn j() {}
+
+// CHECK: define{{( dso_local)?}} void @k()
+#[no_mangle]
+#[inline(always)]
+fn k() {}
+
+// CHECK: define{{( dso_local)?}} void @l()
+#[no_mangle]
+#[inline(always)]
+pub fn l() {}
diff --git a/tests/codegen-llvm/external-no-mangle-statics.rs b/tests/codegen-llvm/external-no-mangle-statics.rs
new file mode 100644
index 00000000000..49f42ee977d
--- /dev/null
+++ b/tests/codegen-llvm/external-no-mangle-statics.rs
@@ -0,0 +1,77 @@
+//@ revisions: lib staticlib
+//@ ignore-emscripten default visibility is hidden
+//@ compile-flags: -Copt-level=3
+//@ [lib] compile-flags: --crate-type lib
+//@ [staticlib] compile-flags: --crate-type staticlib
+// `#[no_mangle]`d static variables always have external linkage, i.e., no `internal` in their
+// definitions
+
+// CHECK-DAG: @A = {{(dso_local )?}}local_unnamed_addr constant
+#[no_mangle]
+static A: u8 = 0;
+
+// CHECK-DAG: @B = {{(dso_local )?}}local_unnamed_addr global
+#[no_mangle]
+static mut B: u8 = 0;
+
+// CHECK-DAG: @C = {{(dso_local )?}}local_unnamed_addr constant
+#[no_mangle]
+pub static C: u8 = 0;
+
+// CHECK-DAG: @D = {{(dso_local )?}}local_unnamed_addr global
+#[no_mangle]
+pub static mut D: u8 = 0;
+
+mod private {
+    // CHECK-DAG: @E = {{(dso_local )?}}local_unnamed_addr constant
+    #[no_mangle]
+    static E: u8 = 0;
+
+    // CHECK-DAG: @F = {{(dso_local )?}}local_unnamed_addr global
+    #[no_mangle]
+    static mut F: u8 = 0;
+
+    // CHECK-DAG: @G = {{(dso_local )?}}local_unnamed_addr constant
+    #[no_mangle]
+    pub static G: u8 = 0;
+
+    // CHECK-DAG: @H = {{(dso_local )?}}local_unnamed_addr global
+    #[no_mangle]
+    pub static mut H: u8 = 0;
+}
+
+const HIDDEN: () = {
+    // CHECK-DAG: @I = {{(dso_local )?}}local_unnamed_addr constant
+    #[no_mangle]
+    static I: u8 = 0;
+
+    // CHECK-DAG: @J = {{(dso_local )?}}local_unnamed_addr global
+    #[no_mangle]
+    static mut J: u8 = 0;
+
+    // CHECK-DAG: @K = {{(dso_local )?}}local_unnamed_addr constant
+    #[no_mangle]
+    pub static K: u8 = 0;
+
+    // CHECK-DAG: @L = {{(dso_local )?}}local_unnamed_addr global
+    #[no_mangle]
+    pub static mut L: u8 = 0;
+};
+
+fn x() {
+    // CHECK-DAG: @M = {{(dso_local )?}}local_unnamed_addr constant
+    #[no_mangle]
+    static M: fn() = x;
+
+    // CHECK-DAG: @N = {{(dso_local )?}}local_unnamed_addr global
+    #[no_mangle]
+    static mut N: u8 = 0;
+
+    // CHECK-DAG: @O = {{(dso_local )?}}local_unnamed_addr constant
+    #[no_mangle]
+    pub static O: u8 = 0;
+
+    // CHECK-DAG: @P = {{(dso_local )?}}local_unnamed_addr global
+    #[no_mangle]
+    pub static mut P: u8 = 0;
+}
diff --git a/tests/codegen-llvm/f128-wasm32-callconv.rs b/tests/codegen-llvm/f128-wasm32-callconv.rs
new file mode 100644
index 00000000000..7dccbda18f1
--- /dev/null
+++ b/tests/codegen-llvm/f128-wasm32-callconv.rs
@@ -0,0 +1,49 @@
+//! Verify that Rust implements the expected calling convention for `f128`
+
+//@ add-core-stubs
+//@ compile-flags: -Copt-level=3 --target wasm32-wasip1
+//@ needs-llvm-components: webassembly
+
+#![crate_type = "lib"]
+#![no_std]
+#![no_core]
+#![feature(no_core, lang_items, f128)]
+
+extern crate minicore;
+
+extern "C" {
+    fn extern_call(arg0: f128);
+    fn extern_ret() -> f128;
+}
+
+#[no_mangle]
+pub extern "C" fn pass(_arg0: u32, arg1: f128) {
+    // CHECK-LABEL: @pass(
+    // an f128 is passed via registers
+    // CHECK-SAME: fp128 noundef %arg1
+    // CHECK: call void @extern_call
+    unsafe { extern_call(arg1) };
+}
+
+// Check that we produce the correct return ABI
+#[no_mangle]
+pub extern "C" fn ret(_arg0: u32, arg1: f128) -> f128 {
+    // CHECK-LABEL: @ret(
+    // but an f128 is returned via the stack
+    // CHECK-SAME: sret
+    // CHECK: store fp128 %arg1
+    // CHECK-NEXT: ret void
+    arg1
+}
+
+// Check that we consume the correct return ABI
+#[no_mangle]
+pub extern "C" fn forward(dst: *mut f128) {
+    // CHECK-LABEL: @forward
+    // CHECK-SAME: ptr{{.*}} %dst)
+    // without optimizatons, an intermediate alloca is used
+    // CHECK: call void @extern_ret
+    // CHECK: store fp128
+    // CHECK: ret void
+    unsafe { *dst = extern_ret() };
+}
diff --git a/tests/codegen-llvm/fastcall-inreg.rs b/tests/codegen-llvm/fastcall-inreg.rs
new file mode 100644
index 00000000000..066943d6e7e
--- /dev/null
+++ b/tests/codegen-llvm/fastcall-inreg.rs
@@ -0,0 +1,40 @@
+// Checks if the "fastcall" calling convention marks function arguments
+// as "inreg" like the C/C++ compilers for the platforms.
+// x86 only.
+
+//@ add-core-stubs
+//@ compile-flags: --target i686-unknown-linux-gnu -Cno-prepopulate-passes -Copt-level=3
+//@ needs-llvm-components: x86
+
+#![crate_type = "lib"]
+#![no_core]
+#![feature(no_core, lang_items)]
+
+extern crate minicore;
+use minicore::*;
+
+pub mod tests {
+    // CHECK: @f1(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 noundef %_3)
+    #[no_mangle]
+    pub extern "fastcall" fn f1(_: i32, _: i32, _: i32) {}
+
+    // CHECK: @f2(ptr inreg noundef %_1, ptr inreg noundef %_2, ptr noundef %_3)
+    #[no_mangle]
+    pub extern "fastcall" fn f2(_: *const i32, _: *const i32, _: *const i32) {}
+
+    // CHECK: @f3(float noundef %_1, i32 inreg noundef %_2, i32 inreg noundef %_3, i32 noundef %_4)
+    #[no_mangle]
+    pub extern "fastcall" fn f3(_: f32, _: i32, _: i32, _: i32) {}
+
+    // CHECK: @f4(i32 inreg noundef %_1, float noundef %_2, i32 inreg noundef %_3, i32 noundef %_4)
+    #[no_mangle]
+    pub extern "fastcall" fn f4(_: i32, _: f32, _: i32, _: i32) {}
+
+    // CHECK: @f5(i64 noundef %_1, i32 noundef %_2)
+    #[no_mangle]
+    pub extern "fastcall" fn f5(_: i64, _: i32) {}
+
+    // CHECK: @f6(i1 inreg noundef zeroext %_1, i32 inreg noundef %_2, i32 noundef %_3)
+    #[no_mangle]
+    pub extern "fastcall" fn f6(_: bool, _: i32, _: i32) {}
+}
diff --git a/tests/codegen-llvm/fatptr.rs b/tests/codegen-llvm/fatptr.rs
new file mode 100644
index 00000000000..041807202b8
--- /dev/null
+++ b/tests/codegen-llvm/fatptr.rs
@@ -0,0 +1,12 @@
+//@ compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+pub trait T {}
+
+// CHECK-LABEL: @copy_fat_ptr
+#[no_mangle]
+pub fn copy_fat_ptr(x: &T) {
+    // CHECK-NOT: extractvalue
+    let x2 = x;
+}
diff --git a/tests/codegen-llvm/fewer-names.rs b/tests/codegen-llvm/fewer-names.rs
new file mode 100644
index 00000000000..ff7a916b619
--- /dev/null
+++ b/tests/codegen-llvm/fewer-names.rs
@@ -0,0 +1,19 @@
+//@ compile-flags: -Coverflow-checks=no -Copt-level=3
+//@ revisions: YES NO
+//@ [YES]compile-flags: -Zfewer-names=yes
+//@ [NO] compile-flags: -Zfewer-names=no
+#![crate_type = "lib"]
+
+#[no_mangle]
+pub fn sum(x: u32, y: u32) -> u32 {
+    // YES-LABEL: define{{.*}}i32 @sum(i32{{.*}} %0, i32{{.*}} %1)
+    // YES-NEXT:    %3 = add i32 %1, %0
+    // YES-NEXT:    ret i32 %3
+
+    // NO-LABEL: define{{.*}}i32 @sum(i32{{.*}} %x, i32{{.*}} %y)
+    // NO-NEXT:  start:
+    // NO-NEXT:    %z = add i32 %y, %x
+    // NO-NEXT:    ret i32 %z
+    let z = x + y;
+    z
+}
diff --git a/tests/codegen-llvm/fixed-x18.rs b/tests/codegen-llvm/fixed-x18.rs
new file mode 100644
index 00000000000..a5767cfa456
--- /dev/null
+++ b/tests/codegen-llvm/fixed-x18.rs
@@ -0,0 +1,23 @@
+// Test that the `reserve-x18` target feature is (not) emitted when
+// the `-Zfixed-x18` flag is (not) set.
+
+//@ add-core-stubs
+//@ revisions: unset set
+//@ needs-llvm-components: aarch64
+//@ compile-flags: --target aarch64-unknown-none
+//@ [set] compile-flags: -Zfixed-x18
+
+#![crate_type = "lib"]
+#![feature(no_core, lang_items)]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+#[no_mangle]
+pub fn foo() {
+    // CHECK: @foo() unnamed_addr #0
+
+    // unset-NOT: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+reserve-x18{{.*}} }
+    // set: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+reserve-x18{{.*}} }
+}
diff --git a/tests/codegen-llvm/float/algebraic.rs b/tests/codegen-llvm/float/algebraic.rs
new file mode 100644
index 00000000000..818a4bcdfe3
--- /dev/null
+++ b/tests/codegen-llvm/float/algebraic.rs
@@ -0,0 +1,149 @@
+// Verify that algebraic intrinsics generate the correct LLVM calls
+
+// Ensure operations get inlined
+//@ compile-flags: -Copt-level=1
+
+#![crate_type = "lib"]
+#![feature(f16)]
+#![feature(f128)]
+#![feature(float_algebraic)]
+
+// CHECK-LABEL: @f16_algebraic_add
+#[no_mangle]
+pub fn f16_algebraic_add(a: f16, b: f16) -> f16 {
+    // CHECK: fadd reassoc nsz arcp contract half %{{.+}}, %{{.+}}
+    a.algebraic_add(b)
+}
+
+// CHECK-LABEL: @f16_algebraic_sub
+#[no_mangle]
+pub fn f16_algebraic_sub(a: f16, b: f16) -> f16 {
+    // CHECK: fsub reassoc nsz arcp contract half %{{.+}}, %{{.+}}
+    a.algebraic_sub(b)
+}
+
+// CHECK-LABEL: @f16_algebraic_mul
+#[no_mangle]
+pub fn f16_algebraic_mul(a: f16, b: f16) -> f16 {
+    // CHECK: fmul reassoc nsz arcp contract half %{{.+}}, %{{.+}}
+    a.algebraic_mul(b)
+}
+
+// CHECK-LABEL: @f16_algebraic_div
+#[no_mangle]
+pub fn f16_algebraic_div(a: f16, b: f16) -> f16 {
+    // CHECK: fdiv reassoc nsz arcp contract half %{{.+}}, %{{.+}}
+    a.algebraic_div(b)
+}
+
+// CHECK-LABEL: @f16_algebraic_rem
+#[no_mangle]
+pub fn f16_algebraic_rem(a: f16, b: f16) -> f16 {
+    // CHECK: frem reassoc nsz arcp contract half %{{.+}}, %{{.+}}
+    a.algebraic_rem(b)
+}
+
+// CHECK-LABEL: @f32_algebraic_add
+#[no_mangle]
+pub fn f32_algebraic_add(a: f32, b: f32) -> f32 {
+    // CHECK: fadd reassoc nsz arcp contract float %{{.+}}, %{{.+}}
+    a.algebraic_add(b)
+}
+
+// CHECK-LABEL: @f32_algebraic_sub
+#[no_mangle]
+pub fn f32_algebraic_sub(a: f32, b: f32) -> f32 {
+    // CHECK: fsub reassoc nsz arcp contract float %{{.+}}, %{{.+}}
+    a.algebraic_sub(b)
+}
+
+// CHECK-LABEL: @f32_algebraic_mul
+#[no_mangle]
+pub fn f32_algebraic_mul(a: f32, b: f32) -> f32 {
+    // CHECK: fmul reassoc nsz arcp contract float %{{.+}}, %{{.+}}
+    a.algebraic_mul(b)
+}
+
+// CHECK-LABEL: @f32_algebraic_div
+#[no_mangle]
+pub fn f32_algebraic_div(a: f32, b: f32) -> f32 {
+    // CHECK: fdiv reassoc nsz arcp contract float %{{.+}}, %{{.+}}
+    a.algebraic_div(b)
+}
+
+// CHECK-LABEL: @f32_algebraic_rem
+#[no_mangle]
+pub fn f32_algebraic_rem(a: f32, b: f32) -> f32 {
+    // CHECK: frem reassoc nsz arcp contract float %{{.+}}, %{{.+}}
+    a.algebraic_rem(b)
+}
+
+// CHECK-LABEL: @f64_algebraic_add
+#[no_mangle]
+pub fn f64_algebraic_add(a: f64, b: f64) -> f64 {
+    // CHECK: fadd reassoc nsz arcp contract double %{{.+}}, %{{.+}}
+    a.algebraic_add(b)
+}
+
+// CHECK-LABEL: @f64_algebraic_sub
+#[no_mangle]
+pub fn f64_algebraic_sub(a: f64, b: f64) -> f64 {
+    // CHECK: fsub reassoc nsz arcp contract double %{{.+}}, %{{.+}}
+    a.algebraic_sub(b)
+}
+
+// CHECK-LABEL: @f64_algebraic_mul
+#[no_mangle]
+pub fn f64_algebraic_mul(a: f64, b: f64) -> f64 {
+    // CHECK: fmul reassoc nsz arcp contract double %{{.+}}, %{{.+}}
+    a.algebraic_mul(b)
+}
+
+// CHECK-LABEL: @f64_algebraic_div
+#[no_mangle]
+pub fn f64_algebraic_div(a: f64, b: f64) -> f64 {
+    // CHECK: fdiv reassoc nsz arcp contract double %{{.+}}, %{{.+}}
+    a.algebraic_div(b)
+}
+
+// CHECK-LABEL: @f64_algebraic_rem
+#[no_mangle]
+pub fn f64_algebraic_rem(a: f64, b: f64) -> f64 {
+    // CHECK: frem reassoc nsz arcp contract double %{{.+}}, %{{.+}}
+    a.algebraic_rem(b)
+}
+
+// CHECK-LABEL: @f128_algebraic_add
+#[no_mangle]
+pub fn f128_algebraic_add(a: f128, b: f128) -> f128 {
+    // CHECK: fadd reassoc nsz arcp contract fp128 %{{.+}}, %{{.+}}
+    a.algebraic_add(b)
+}
+
+// CHECK-LABEL: @f128_algebraic_sub
+#[no_mangle]
+pub fn f128_algebraic_sub(a: f128, b: f128) -> f128 {
+    // CHECK: fsub reassoc nsz arcp contract fp128 %{{.+}}, %{{.+}}
+    a.algebraic_sub(b)
+}
+
+// CHECK-LABEL: @f128_algebraic_mul
+#[no_mangle]
+pub fn f128_algebraic_mul(a: f128, b: f128) -> f128 {
+    // CHECK: fmul reassoc nsz arcp contract fp128 %{{.+}}, %{{.+}}
+    a.algebraic_mul(b)
+}
+
+// CHECK-LABEL: @f128_algebraic_div
+#[no_mangle]
+pub fn f128_algebraic_div(a: f128, b: f128) -> f128 {
+    // CHECK: fdiv reassoc nsz arcp contract fp128 %{{.+}}, %{{.+}}
+    a.algebraic_div(b)
+}
+
+// CHECK-LABEL: @f128_algebraic_rem
+#[no_mangle]
+pub fn f128_algebraic_rem(a: f128, b: f128) -> f128 {
+    // CHECK: frem reassoc nsz arcp contract fp128 %{{.+}}, %{{.+}}
+    a.algebraic_rem(b)
+}
diff --git a/tests/codegen-llvm/float/f128.rs b/tests/codegen-llvm/float/f128.rs
new file mode 100644
index 00000000000..d87bab1172a
--- /dev/null
+++ b/tests/codegen-llvm/float/f128.rs
@@ -0,0 +1,441 @@
+// 32-bit x86 returns float types differently to avoid the x87 stack.
+// 32-bit systems will return 128bit values using a return area pointer.
+// Emscripten aligns f128 to 8 bytes, not 16.
+//@ revisions: x86-sse x86-nosse bit32 bit64 emscripten
+//@[x86-sse] only-x86
+//@[x86-sse] only-rustc_abi-x86-sse2
+//@[x86-nosse] only-x86
+//@[x86-nosse] ignore-rustc_abi-x86-sse2
+//@[bit32] ignore-x86
+//@[bit32] ignore-emscripten
+//@[bit32] only-32bit
+//@[bit64] ignore-x86
+//@[bit64] ignore-emscripten
+//@[bit64] only-64bit
+//@[emscripten] only-emscripten
+
+// Verify that our intrinsics generate the correct LLVM calls for f128
+
+#![crate_type = "lib"]
+#![feature(f128)]
+#![feature(f16)]
+#![feature(core_intrinsics)]
+
+// CHECK-LABEL: i1 @f128_eq(
+#[no_mangle]
+pub fn f128_eq(a: f128, b: f128) -> bool {
+    // CHECK: fcmp oeq fp128 %{{.+}}, %{{.+}}
+    a == b
+}
+
+// CHECK-LABEL: i1 @f128_ne(
+#[no_mangle]
+pub fn f128_ne(a: f128, b: f128) -> bool {
+    // CHECK: fcmp une fp128 %{{.+}}, %{{.+}}
+    a != b
+}
+
+// CHECK-LABEL: i1 @f128_gt(
+#[no_mangle]
+pub fn f128_gt(a: f128, b: f128) -> bool {
+    // CHECK: fcmp ogt fp128 %{{.+}}, %{{.+}}
+    a > b
+}
+
+// CHECK-LABEL: i1 @f128_ge(
+#[no_mangle]
+pub fn f128_ge(a: f128, b: f128) -> bool {
+    // CHECK: fcmp oge fp128 %{{.+}}, %{{.+}}
+    a >= b
+}
+
+// CHECK-LABEL: i1 @f128_lt(
+#[no_mangle]
+pub fn f128_lt(a: f128, b: f128) -> bool {
+    // CHECK: fcmp olt fp128 %{{.+}}, %{{.+}}
+    a < b
+}
+
+// CHECK-LABEL: i1 @f128_le(
+#[no_mangle]
+pub fn f128_le(a: f128, b: f128) -> bool {
+    // CHECK: fcmp ole fp128 %{{.+}}, %{{.+}}
+    a <= b
+}
+
+// x86-nosse-LABEL: void @f128_neg({{.*}}sret([16 x i8])
+// x86-sse-LABEL: <16 x i8> @f128_neg(fp128
+// bit32-LABEL: void @f128_neg({{.*}}sret([16 x i8])
+// bit64-LABEL: fp128 @f128_neg(
+// emscripten-LABEL: void @f128_neg({{.*}}sret([16 x i8])
+#[no_mangle]
+pub fn f128_neg(a: f128) -> f128 {
+    // CHECK: fneg fp128
+    -a
+}
+
+// x86-nosse-LABEL: void @f128_add({{.*}}sret([16 x i8])
+// x86-sse-LABEL: <16 x i8> @f128_add(fp128
+// bit32-LABEL: void @f128_add({{.*}}sret([16 x i8])
+// bit64-LABEL: fp128 @f128_add(
+// emscripten-LABEL: void @f128_add({{.*}}sret([16 x i8])
+#[no_mangle]
+pub fn f128_add(a: f128, b: f128) -> f128 {
+    // CHECK: fadd fp128 %{{.+}}, %{{.+}}
+    a + b
+}
+
+// x86-nosse-LABEL: void @f128_sub({{.*}}sret([16 x i8])
+// x86-sse-LABEL: <16 x i8> @f128_sub(fp128
+// bit32-LABEL: void @f128_sub({{.*}}sret([16 x i8])
+// bit64-LABEL: fp128 @f128_sub(
+// emscripten-LABEL: void @f128_sub({{.*}}sret([16 x i8])
+#[no_mangle]
+pub fn f128_sub(a: f128, b: f128) -> f128 {
+    // CHECK: fsub fp128 %{{.+}}, %{{.+}}
+    a - b
+}
+
+// x86-nosse-LABEL: void @f128_mul({{.*}}sret([16 x i8])
+// x86-sse-LABEL: <16 x i8> @f128_mul(fp128
+// bit32-LABEL: void @f128_mul({{.*}}sret([16 x i8])
+// bit64-LABEL: fp128 @f128_mul(
+// emscripten-LABEL: void @f128_mul({{.*}}sret([16 x i8])
+#[no_mangle]
+pub fn f128_mul(a: f128, b: f128) -> f128 {
+    // CHECK: fmul fp128 %{{.+}}, %{{.+}}
+    a * b
+}
+
+// x86-nosse-LABEL: void @f128_div({{.*}}sret([16 x i8])
+// x86-sse-LABEL: <16 x i8> @f128_div(fp128
+// bit32-LABEL: void @f128_div({{.*}}sret([16 x i8])
+// bit64-LABEL: fp128 @f128_div(
+// emscripten-LABEL: void @f128_div({{.*}}sret([16 x i8])
+#[no_mangle]
+pub fn f128_div(a: f128, b: f128) -> f128 {
+    // CHECK: fdiv fp128 %{{.+}}, %{{.+}}
+    a / b
+}
+
+// x86-nosse-LABEL: void @f128_rem({{.*}}sret([16 x i8])
+// x86-sse-LABEL: <16 x i8> @f128_rem(fp128
+// bit32-LABEL: void @f128_rem({{.*}}sret([16 x i8])
+// bit64-LABEL: fp128 @f128_rem(
+// emscripten-LABEL: void @f128_rem({{.*}}sret([16 x i8])
+#[no_mangle]
+pub fn f128_rem(a: f128, b: f128) -> f128 {
+    // CHECK: frem fp128 %{{.+}}, %{{.+}}
+    a % b
+}
+
+// CHECK-LABEL: void @f128_add_assign(
+#[no_mangle]
+pub fn f128_add_assign(a: &mut f128, b: f128) {
+    // CHECK: fadd fp128 %{{.+}}, %{{.+}}
+    // CHECK-NEXT: store fp128 %{{.+}}, ptr %{{.+}}
+    *a += b;
+}
+
+// CHECK-LABEL: void @f128_sub_assign(
+#[no_mangle]
+pub fn f128_sub_assign(a: &mut f128, b: f128) {
+    // CHECK: fsub fp128 %{{.+}}, %{{.+}}
+    // CHECK-NEXT: store fp128 %{{.+}}, ptr %{{.+}}
+    *a -= b;
+}
+
+// CHECK-LABEL: void @f128_mul_assign(
+#[no_mangle]
+pub fn f128_mul_assign(a: &mut f128, b: f128) {
+    // CHECK: fmul fp128 %{{.+}}, %{{.+}}
+    // CHECK-NEXT: store fp128 %{{.+}}, ptr %{{.+}}
+    *a *= b
+}
+
+// CHECK-LABEL: void @f128_div_assign(
+#[no_mangle]
+pub fn f128_div_assign(a: &mut f128, b: f128) {
+    // CHECK: fdiv fp128 %{{.+}}, %{{.+}}
+    // CHECK-NEXT: store fp128 %{{.+}}, ptr %{{.+}}
+    *a /= b
+}
+
+// CHECK-LABEL: void @f128_rem_assign(
+#[no_mangle]
+pub fn f128_rem_assign(a: &mut f128, b: f128) {
+    // CHECK: frem fp128 %{{.+}}, %{{.+}}
+    // CHECK-NEXT: store fp128 %{{.+}}, ptr %{{.+}}
+    *a %= b
+}
+
+/* float to float conversions */
+
+// x86-sse-LABEL: <2 x i8> @f128_as_f16(
+// x86-nosse-LABEL: i16 @f128_as_f16(
+// bits32-LABEL: half @f128_as_f16(
+// bits64-LABEL: half @f128_as_f16(
+#[no_mangle]
+pub fn f128_as_f16(a: f128) -> f16 {
+    // CHECK: fptrunc fp128 %{{.+}} to half
+    a as f16
+}
+
+// x86-sse-LABEL: <4 x i8> @f128_as_f32(
+// x86-nosse-LABEL: i32 @f128_as_f32(
+// bit32-LABEL: float @f128_as_f32(
+// bit64-LABEL: float @f128_as_f32(
+// emscripten-LABEL: float @f128_as_f32(
+#[no_mangle]
+pub fn f128_as_f32(a: f128) -> f32 {
+    // CHECK: fptrunc fp128 %{{.+}} to float
+    a as f32
+}
+
+// x86-sse-LABEL: <8 x i8> @f128_as_f64(
+// x86-nosse-LABEL: void @f128_as_f64({{.*}}sret([8 x i8])
+// bit32-LABEL: double @f128_as_f64(
+// bit64-LABEL: double @f128_as_f64(
+// emscripten-LABEL: double @f128_as_f64(
+#[no_mangle]
+pub fn f128_as_f64(a: f128) -> f64 {
+    // CHECK: fptrunc fp128 %{{.+}} to double
+    a as f64
+}
+
+// x86-sse-LABEL: <16 x i8> @f128_as_self(
+// x86-nosse-LABEL: void @f128_as_self({{.*}}sret([16 x i8])
+// bit32-LABEL: void @f128_as_self({{.*}}sret([16 x i8])
+// bit64-LABEL: fp128 @f128_as_self(
+// emscripten-LABEL: void @f128_as_self({{.*}}sret([16 x i8])
+#[no_mangle]
+pub fn f128_as_self(a: f128) -> f128 {
+    // x86: store fp128 %a, ptr %_0, align 16
+    // bit32: store fp128 %a, ptr %_0, align 16
+    // bit64: ret fp128 %{{.+}}
+    // emscripten: store fp128 %a, ptr %_0, align 8
+    a as f128
+}
+
+// x86-sse-LABEL: <16 x i8> @f16_as_f128(
+// x86-nosse-LABEL: void @f16_as_f128({{.*}}sret([16 x i8])
+// bit32-LABEL: void @f16_as_f128({{.*}}sret([16 x i8])
+// bit64-LABEL: fp128 @f16_as_f128(
+// emscripten-LABEL: void @f16_as_f128({{.*}}sret([16 x i8])
+#[no_mangle]
+pub fn f16_as_f128(a: f16) -> f128 {
+    // CHECK: fpext half %{{.+}} to fp128
+    a as f128
+}
+
+// x86-sse-LABEL: <16 x i8> @f32_as_f128(
+// x86-nosse-LABEL: void @f32_as_f128({{.*}}sret([16 x i8])
+// bit32-LABEL: void @f32_as_f128({{.*}}sret([16 x i8])
+// bit64-LABEL: fp128 @f32_as_f128(
+// emscripten-LABEL: void @f32_as_f128({{.*}}sret([16 x i8])
+#[no_mangle]
+pub fn f32_as_f128(a: f32) -> f128 {
+    // CHECK: fpext float %{{.+}} to fp128
+    a as f128
+}
+
+// x86-sse-LABEL: <16 x i8> @f64_as_f128(
+// x86-nosse-LABEL: void @f64_as_f128({{.*}}sret([16 x i8])
+// bit32-LABEL: void @f64_as_f128({{.*}}sret([16 x i8])
+// bit64-LABEL: fp128 @f64_as_f128(
+// emscripten-LABEL: void @f64_as_f128({{.*}}sret([16 x i8])
+#[no_mangle]
+pub fn f64_as_f128(a: f64) -> f128 {
+    // CHECK: fpext double %{{.+}} to fp128
+    a as f128
+}
+
+/* float to int conversions */
+
+// CHECK-LABEL: i8 @f128_as_u8(
+#[no_mangle]
+pub fn f128_as_u8(a: f128) -> u8 {
+    // CHECK: call i8 @llvm.fptoui.sat.i8.f128(fp128 %{{.+}})
+    a as u8
+}
+
+#[no_mangle]
+pub fn f128_as_u16(a: f128) -> u16 {
+    // CHECK: call i16 @llvm.fptoui.sat.i16.f128(fp128 %{{.+}})
+    a as u16
+}
+
+// CHECK-LABEL: i32 @f128_as_u32(
+#[no_mangle]
+pub fn f128_as_u32(a: f128) -> u32 {
+    // CHECK: call i32 @llvm.fptoui.sat.i32.f128(fp128 %{{.+}})
+    a as u32
+}
+
+// CHECK-LABEL: i64 @f128_as_u64(
+#[no_mangle]
+pub fn f128_as_u64(a: f128) -> u64 {
+    // CHECK: call i64 @llvm.fptoui.sat.i64.f128(fp128 %{{.+}})
+    a as u64
+}
+
+// x86-sse-LABEL: void @f128_as_u128({{.*}}sret([16 x i8])
+// x86-nosse-LABEL: void @f128_as_u128({{.*}}sret([16 x i8])
+// bit32-LABEL: void @f128_as_u128({{.*}}sret([16 x i8])
+// bit64-LABEL: i128 @f128_as_u128(
+// emscripten-LABEL: void @f128_as_u128({{.*}}sret([16 x i8])
+#[no_mangle]
+pub fn f128_as_u128(a: f128) -> u128 {
+    // CHECK: call i128 @llvm.fptoui.sat.i128.f128(fp128 %{{.+}})
+    a as u128
+}
+
+// CHECK-LABEL: i8 @f128_as_i8(
+#[no_mangle]
+pub fn f128_as_i8(a: f128) -> i8 {
+    // CHECK: call i8 @llvm.fptosi.sat.i8.f128(fp128 %{{.+}})
+    a as i8
+}
+
+// CHECK-LABEL: i16 @f128_as_i16(
+#[no_mangle]
+pub fn f128_as_i16(a: f128) -> i16 {
+    // CHECK: call i16 @llvm.fptosi.sat.i16.f128(fp128 %{{.+}})
+    a as i16
+}
+// CHECK-LABEL: i32 @f128_as_i32(
+#[no_mangle]
+pub fn f128_as_i32(a: f128) -> i32 {
+    // CHECK: call i32 @llvm.fptosi.sat.i32.f128(fp128 %{{.+}})
+    a as i32
+}
+
+// CHECK-LABEL: i64 @f128_as_i64(
+#[no_mangle]
+pub fn f128_as_i64(a: f128) -> i64 {
+    // CHECK: call i64 @llvm.fptosi.sat.i64.f128(fp128 %{{.+}})
+    a as i64
+}
+
+// x86-sse-LABEL: void @f128_as_i128({{.*}}sret([16 x i8])
+// x86-nosse-LABEL: void @f128_as_i128({{.*}}sret([16 x i8])
+// bit32-LABEL: void @f128_as_i128({{.*}}sret([16 x i8])
+// bit64-LABEL: i128 @f128_as_i128(
+// emscripten-LABEL: void @f128_as_i128({{.*}}sret([16 x i8])
+#[no_mangle]
+pub fn f128_as_i128(a: f128) -> i128 {
+    // CHECK: call i128 @llvm.fptosi.sat.i128.f128(fp128 %{{.+}})
+    a as i128
+}
+
+/* int to float conversions */
+
+// x86-sse-LABEL: <16 x i8> @u8_as_f128(
+// x86-nosse-LABEL: void @u8_as_f128({{.*}}sret([16 x i8])
+// bit32-LABEL: void @u8_as_f128({{.*}}sret([16 x i8])
+// bit64-LABEL: fp128 @u8_as_f128(
+// emscripten-LABEL: void @u8_as_f128({{.*}}sret([16 x i8])
+#[no_mangle]
+pub fn u8_as_f128(a: u8) -> f128 {
+    // CHECK: uitofp i8 %{{.+}} to fp128
+    a as f128
+}
+
+// x86-sse-LABEL: <16 x i8> @u16_as_f128(
+// x86-nosse-LABEL: void @u16_as_f128({{.*}}sret([16 x i8])
+// bit32-LABEL: void @u16_as_f128({{.*}}sret([16 x i8])
+// bit64-LABEL: fp128 @u16_as_f128(
+// emscripten-LABEL: void @u16_as_f128({{.*}}sret([16 x i8])
+#[no_mangle]
+pub fn u16_as_f128(a: u16) -> f128 {
+    // CHECK: uitofp i16 %{{.+}} to fp128
+    a as f128
+}
+
+// x86-sse-LABEL: <16 x i8> @u32_as_f128(
+// x86-nosse-LABEL: void @u32_as_f128({{.*}}sret([16 x i8])
+// bit32-LABEL: void @u32_as_f128({{.*}}sret([16 x i8])
+// bit64-LABEL: fp128 @u32_as_f128(
+// emscripten-LABEL: void @u32_as_f128({{.*}}sret([16 x i8])
+#[no_mangle]
+pub fn u32_as_f128(a: u32) -> f128 {
+    // CHECK: uitofp i32 %{{.+}} to fp128
+    a as f128
+}
+
+// x86-sse-LABEL: <16 x i8> @u64_as_f128(
+// x86-nosse-LABEL: void @u64_as_f128({{.*}}sret([16 x i8])
+// bit32-LABEL: void @u64_as_f128({{.*}}sret([16 x i8])
+// bit64-LABEL: fp128 @u64_as_f128(
+// emscripten-LABEL: void @u64_as_f128({{.*}}sret([16 x i8])
+#[no_mangle]
+pub fn u64_as_f128(a: u64) -> f128 {
+    // CHECK: uitofp i64 %{{.+}} to fp128
+    a as f128
+}
+
+// x86-sse-LABEL: <16 x i8> @u128_as_f128(
+// x86-nosse-LABEL: void @u128_as_f128({{.*}}sret([16 x i8])
+// bit32-LABEL: void @u128_as_f128({{.*}}sret([16 x i8])
+// bit64-LABEL: fp128 @u128_as_f128(
+// emscripten-LABEL: void @u128_as_f128({{.*}}sret([16 x i8])
+#[no_mangle]
+pub fn u128_as_f128(a: u128) -> f128 {
+    // CHECK: uitofp i128 %{{.+}} to fp128
+    a as f128
+}
+
+// x86-sse-LABEL: <16 x i8> @i8_as_f128(
+// x86-nosse-LABEL: void @i8_as_f128({{.*}}sret([16 x i8])
+// bit32-LABEL: void @i8_as_f128({{.*}}sret([16 x i8])
+// bit64-LABEL: fp128 @i8_as_f128(
+// emscripten-LABEL: void @i8_as_f128({{.*}}sret([16 x i8])
+#[no_mangle]
+pub fn i8_as_f128(a: i8) -> f128 {
+    // CHECK: sitofp i8 %{{.+}} to fp128
+    a as f128
+}
+
+// x86-sse-LABEL: <16 x i8> @i16_as_f128(
+// x86-nosse-LABEL: void @i16_as_f128({{.*}}sret([16 x i8])
+// bit32-LABEL: void @i16_as_f128({{.*}}sret([16 x i8])
+// bit64-LABEL: fp128 @i16_as_f128(
+// emscripten-LABEL: void @i16_as_f128({{.*}}sret([16 x i8])
+#[no_mangle]
+pub fn i16_as_f128(a: i16) -> f128 {
+    // CHECK: sitofp i16 %{{.+}} to fp128
+    a as f128
+}
+
+// x86-sse-LABEL: <16 x i8> @i32_as_f128(
+// x86-nosse-LABEL: void @i32_as_f128({{.*}}sret([16 x i8])
+// bit32-LABEL: void @i32_as_f128({{.*}}sret([16 x i8])
+// bit64-LABEL: fp128 @i32_as_f128(
+// emscripten-LABEL: void @i32_as_f128({{.*}}sret([16 x i8])
+#[no_mangle]
+pub fn i32_as_f128(a: i32) -> f128 {
+    // CHECK: sitofp i32 %{{.+}} to fp128
+    a as f128
+}
+
+// x86-sse-LABEL: <16 x i8> @i64_as_f128(
+// x86-nosse-LABEL: void @i64_as_f128({{.*}}sret([16 x i8])
+// bit32-LABEL: void @i64_as_f128({{.*}}sret([16 x i8])
+// bit64-LABEL: fp128 @i64_as_f128(
+// emscripten-LABEL: void @i64_as_f128({{.*}}sret([16 x i8])
+#[no_mangle]
+pub fn i64_as_f128(a: i64) -> f128 {
+    // CHECK: sitofp i64 %{{.+}} to fp128
+    a as f128
+}
+
+// x86-sse-LABEL: <16 x i8> @i128_as_f128(
+// x86-nosse-LABEL: void @i128_as_f128({{.*}}sret([16 x i8])
+// bit32-LABEL: void @i128_as_f128({{.*}}sret([16 x i8])
+// bit64-LABEL: fp128 @i128_as_f128(
+// emscripten-LABEL: void @i128_as_f128({{.*}}sret([16 x i8])
+#[no_mangle]
+pub fn i128_as_f128(a: i128) -> f128 {
+    // CHECK: sitofp i128 %{{.+}} to fp128
+    a as f128
+}
diff --git a/tests/codegen-llvm/float/f16-f128-inline.rs b/tests/codegen-llvm/float/f16-f128-inline.rs
new file mode 100644
index 00000000000..aa2c38c209e
--- /dev/null
+++ b/tests/codegen-llvm/float/f16-f128-inline.rs
@@ -0,0 +1,29 @@
+//@ revisions: default nopt
+//@[nopt] compile-flags: -Copt-level=0 -Zcross-crate-inline-threshold=never -Zmir-opt-level=0 -Cno-prepopulate-passes
+
+// Ensure that functions using `f16` and `f128` are always inlined to avoid crashes
+// when the backend does not support these types.
+
+#![crate_type = "lib"]
+#![feature(f128)]
+#![feature(f16)]
+
+pub fn f16_arg(_a: f16) {
+    // CHECK-NOT: f16_arg
+    todo!()
+}
+
+pub fn f16_ret() -> f16 {
+    // CHECK-NOT: f16_ret
+    todo!()
+}
+
+pub fn f128_arg(_a: f128) {
+    // CHECK-NOT: f128_arg
+    todo!()
+}
+
+pub fn f128_ret() -> f128 {
+    // CHECK-NOT: f128_ret
+    todo!()
+}
diff --git a/tests/codegen-llvm/float/f16.rs b/tests/codegen-llvm/float/f16.rs
new file mode 100644
index 00000000000..0c40606ad8a
--- /dev/null
+++ b/tests/codegen-llvm/float/f16.rs
@@ -0,0 +1,364 @@
+// 32-bit x86 returns float types differently to avoid the x87 stack.
+// 32-bit systems will return 128bit values using a return area pointer.
+//@ revisions: x86-sse x86-nosse bit32 bit64
+//@[x86-sse] only-x86
+//@[x86-sse] only-rustc_abi-x86-sse2
+//@[x86-nosse] only-x86
+//@[x86-nosse] ignore-rustc_abi-x86-sse2
+//@[bit32] ignore-x86
+//@[bit32] only-32bit
+//@[bit64] ignore-x86
+//@[bit64] only-64bit
+
+// Verify that our intrinsics generate the correct LLVM calls for f16
+
+#![crate_type = "lib"]
+#![feature(f128)]
+#![feature(f16)]
+#![feature(core_intrinsics)]
+
+/* arithmetic */
+
+// CHECK-LABEL: i1 @f16_eq(
+#[no_mangle]
+pub fn f16_eq(a: f16, b: f16) -> bool {
+    // CHECK: fcmp oeq half %{{.+}}, %{{.+}}
+    a == b
+}
+
+// CHECK-LABEL: i1 @f16_ne(
+#[no_mangle]
+pub fn f16_ne(a: f16, b: f16) -> bool {
+    // CHECK: fcmp une half %{{.+}}, %{{.+}}
+    a != b
+}
+
+// CHECK-LABEL: i1 @f16_gt(
+#[no_mangle]
+pub fn f16_gt(a: f16, b: f16) -> bool {
+    // CHECK: fcmp ogt half %{{.+}}, %{{.+}}
+    a > b
+}
+
+// CHECK-LABEL: i1 @f16_ge(
+#[no_mangle]
+pub fn f16_ge(a: f16, b: f16) -> bool {
+    // CHECK: fcmp oge half %{{.+}}, %{{.+}}
+    a >= b
+}
+
+// CHECK-LABEL: i1 @f16_lt(
+#[no_mangle]
+pub fn f16_lt(a: f16, b: f16) -> bool {
+    // CHECK: fcmp olt half %{{.+}}, %{{.+}}
+    a < b
+}
+
+// CHECK-LABEL: i1 @f16_le(
+#[no_mangle]
+pub fn f16_le(a: f16, b: f16) -> bool {
+    // CHECK: fcmp ole half %{{.+}}, %{{.+}}
+    a <= b
+}
+
+// This is where we check the argument and return ABI for f16.
+// bit32-LABEL: half @f16_neg(half
+// bit64-LABEL: half @f16_neg(half
+// x86-sse-LABEL: <2 x i8> @f16_neg(half
+// x86-nosse-LABEL: i16 @f16_neg(half
+#[no_mangle]
+pub fn f16_neg(a: f16) -> f16 {
+    // CHECK: fneg half %{{.+}}
+    -a
+}
+
+// CHECK-LABEL: @f16_add
+#[no_mangle]
+pub fn f16_add(a: f16, b: f16) -> f16 {
+    // CHECK: fadd half %{{.+}}, %{{.+}}
+    a + b
+}
+
+// CHECK-LABEL: @f16_sub
+#[no_mangle]
+pub fn f16_sub(a: f16, b: f16) -> f16 {
+    // CHECK: fsub half %{{.+}}, %{{.+}}
+    a - b
+}
+
+// CHECK-LABEL: @f16_mul
+#[no_mangle]
+pub fn f16_mul(a: f16, b: f16) -> f16 {
+    // CHECK: fmul half %{{.+}}, %{{.+}}
+    a * b
+}
+
+// CHECK-LABEL: @f16_div
+#[no_mangle]
+pub fn f16_div(a: f16, b: f16) -> f16 {
+    // CHECK: fdiv half %{{.+}}, %{{.+}}
+    a / b
+}
+
+// CHECK-LABEL: @f16_rem
+#[no_mangle]
+pub fn f16_rem(a: f16, b: f16) -> f16 {
+    // CHECK: frem half %{{.+}}, %{{.+}}
+    a % b
+}
+
+// CHECK-LABEL: void @f16_add_assign(
+#[no_mangle]
+pub fn f16_add_assign(a: &mut f16, b: f16) {
+    // CHECK: fadd half %{{.+}}, %{{.+}}
+    // CHECK-NEXT: store half %{{.+}}, ptr %{{.+}}
+    *a += b;
+}
+
+// CHECK-LABEL: void @f16_sub_assign(
+#[no_mangle]
+pub fn f16_sub_assign(a: &mut f16, b: f16) {
+    // CHECK: fsub half %{{.+}}, %{{.+}}
+    // CHECK-NEXT: store half %{{.+}}, ptr %{{.+}}
+    *a -= b;
+}
+
+// CHECK-LABEL: void @f16_mul_assign(
+#[no_mangle]
+pub fn f16_mul_assign(a: &mut f16, b: f16) {
+    // CHECK: fmul half %{{.+}}, %{{.+}}
+    // CHECK-NEXT: store half %{{.+}}, ptr %{{.+}}
+    *a *= b;
+}
+
+// CHECK-LABEL: void @f16_div_assign(
+#[no_mangle]
+pub fn f16_div_assign(a: &mut f16, b: f16) {
+    // CHECK: fdiv half %{{.+}}, %{{.+}}
+    // CHECK-NEXT: store half %{{.+}}, ptr %{{.+}}
+    *a /= b;
+}
+
+// CHECK-LABEL: void @f16_rem_assign(
+#[no_mangle]
+pub fn f16_rem_assign(a: &mut f16, b: f16) {
+    // CHECK: frem half %{{.+}}, %{{.+}}
+    // CHECK-NEXT: store half %{{.+}}, ptr %{{.+}}
+    *a %= b;
+}
+
+/* float to float conversions */
+
+// bit32-LABEL: half @f16_as_self(
+// bit64-LABEL: half @f16_as_self(
+// x86-sse-LABEL: <2 x i8> @f16_as_self(
+// x86-nosse-LABEL: i16 @f16_as_self(
+#[no_mangle]
+pub fn f16_as_self(a: f16) -> f16 {
+    // bit32-CHECK: ret half %{{.+}}
+    // bit64-CHECK: ret half %{{.+}}
+    // x86-sse-CHECK: bitcast half
+    // x86-nosse-CHECK: bitcast half
+    // x86-sse-CHECK: ret i16
+    // x86-nosse-CHECK: ret i16
+    a as f16
+}
+
+// x86-sse-LABEL: <4 x i8> @f16_as_f32(
+// x86-nosse-LABEL: i32 @f16_as_f32(
+// bit32-LABEL: float @f16_as_f32(
+// bit64-LABEL: float @f16_as_f32(
+#[no_mangle]
+pub fn f16_as_f32(a: f16) -> f32 {
+    // CHECK: fpext half %{{.+}} to float
+    a as f32
+}
+
+// x86-sse-LABEL: <8 x i8> @f16_as_f64(
+// x86-nosse-LABEL: void @f16_as_f64({{.*}}sret([8 x i8])
+// bit32-LABEL: double @f16_as_f64(
+// bit64-LABEL: double @f16_as_f64(
+#[no_mangle]
+pub fn f16_as_f64(a: f16) -> f64 {
+    // CHECK: fpext half %{{.+}} to double
+    a as f64
+}
+
+// x86-sse-LABEL: <16 x i8> @f16_as_f128(
+// x86-nosse-LABEL: void @f16_as_f128({{.*}}sret([16 x i8])
+// bit32-LABEL: void @f16_as_f128({{.*}}sret([16 x i8])
+// bit64-LABEL: fp128 @f16_as_f128(
+#[no_mangle]
+pub fn f16_as_f128(a: f16) -> f128 {
+    // CHECK: fpext half %{{.+}} to fp128
+    a as f128
+}
+
+// CHECK-LABEL: @f32_as_f16
+#[no_mangle]
+pub fn f32_as_f16(a: f32) -> f16 {
+    // CHECK: fptrunc float %{{.+}} to half
+    a as f16
+}
+
+// CHECK-LABEL: @f64_as_f16
+#[no_mangle]
+pub fn f64_as_f16(a: f64) -> f16 {
+    // CHECK: fptrunc double %{{.+}} to half
+    a as f16
+}
+
+// CHECK-LABEL: @f128_as_f16
+#[no_mangle]
+pub fn f128_as_f16(a: f128) -> f16 {
+    // CHECK: fptrunc fp128 %{{.+}} to half
+    a as f16
+}
+
+/* float to int conversions */
+
+// CHECK-LABEL: i8 @f16_as_u8(
+#[no_mangle]
+pub fn f16_as_u8(a: f16) -> u8 {
+    // CHECK: call i8 @llvm.fptoui.sat.i8.f16(half %{{.+}})
+    a as u8
+}
+
+#[no_mangle]
+pub fn f16_as_u16(a: f16) -> u16 {
+    // CHECK: call i16 @llvm.fptoui.sat.i16.f16(half %{{.+}})
+    a as u16
+}
+
+// CHECK-LABEL: i32 @f16_as_u32(
+#[no_mangle]
+pub fn f16_as_u32(a: f16) -> u32 {
+    // CHECK: call i32 @llvm.fptoui.sat.i32.f16(half %{{.+}})
+    a as u32
+}
+
+// CHECK-LABEL: i64 @f16_as_u64(
+#[no_mangle]
+pub fn f16_as_u64(a: f16) -> u64 {
+    // CHECK: call i64 @llvm.fptoui.sat.i64.f16(half %{{.+}})
+    a as u64
+}
+
+// x86-sse-LABEL: void @f16_as_u128({{.*}}sret([16 x i8])
+// x86-nosse-LABEL: void @f16_as_u128({{.*}}sret([16 x i8])
+// bit32-LABEL: void @f16_as_u128({{.*}}sret([16 x i8])
+// bit64-LABEL: i128 @f16_as_u128(
+#[no_mangle]
+pub fn f16_as_u128(a: f16) -> u128 {
+    // CHECK: call i128 @llvm.fptoui.sat.i128.f16(half %{{.+}})
+    a as u128
+}
+
+// CHECK-LABEL: i8 @f16_as_i8(
+#[no_mangle]
+pub fn f16_as_i8(a: f16) -> i8 {
+    // CHECK: call i8 @llvm.fptosi.sat.i8.f16(half %{{.+}})
+    a as i8
+}
+
+// CHECK-LABEL: i16 @f16_as_i16(
+#[no_mangle]
+pub fn f16_as_i16(a: f16) -> i16 {
+    // CHECK: call i16 @llvm.fptosi.sat.i16.f16(half %{{.+}})
+    a as i16
+}
+// CHECK-LABEL: i32 @f16_as_i32(
+#[no_mangle]
+pub fn f16_as_i32(a: f16) -> i32 {
+    // CHECK: call i32 @llvm.fptosi.sat.i32.f16(half %{{.+}})
+    a as i32
+}
+
+// CHECK-LABEL: i64 @f16_as_i64(
+#[no_mangle]
+pub fn f16_as_i64(a: f16) -> i64 {
+    // CHECK: call i64 @llvm.fptosi.sat.i64.f16(half %{{.+}})
+    a as i64
+}
+
+// x86-sse-LABEL: void @f16_as_i128({{.*}}sret([16 x i8])
+// x86-nosse-LABEL: void @f16_as_i128({{.*}}sret([16 x i8])
+// bit32-LABEL: void @f16_as_i128({{.*}}sret([16 x i8])
+// bit64-LABEL: i128 @f16_as_i128(
+#[no_mangle]
+pub fn f16_as_i128(a: f16) -> i128 {
+    // CHECK: call i128 @llvm.fptosi.sat.i128.f16(half %{{.+}})
+    a as i128
+}
+
+/* int to float conversions */
+
+// CHECK-LABEL: @u8_as_f16
+#[no_mangle]
+pub fn u8_as_f16(a: u8) -> f16 {
+    // CHECK: uitofp i8 %{{.+}} to half
+    a as f16
+}
+
+// CHECK-LABEL: @u16_as_f16
+#[no_mangle]
+pub fn u16_as_f16(a: u16) -> f16 {
+    // CHECK: uitofp i16 %{{.+}} to half
+    a as f16
+}
+
+// CHECK-LABEL: @u32_as_f16
+#[no_mangle]
+pub fn u32_as_f16(a: u32) -> f16 {
+    // CHECK: uitofp i32 %{{.+}} to half
+    a as f16
+}
+
+// CHECK-LABEL: @u64_as_f16
+#[no_mangle]
+pub fn u64_as_f16(a: u64) -> f16 {
+    // CHECK: uitofp i64 %{{.+}} to half
+    a as f16
+}
+
+// CHECK-LABEL: @u128_as_f16
+#[no_mangle]
+pub fn u128_as_f16(a: u128) -> f16 {
+    // CHECK: uitofp i128 %{{.+}} to half
+    a as f16
+}
+
+// CHECK-LABEL: @i8_as_f16
+#[no_mangle]
+pub fn i8_as_f16(a: i8) -> f16 {
+    // CHECK: sitofp i8 %{{.+}} to half
+    a as f16
+}
+
+// CHECK-LABEL: @i16_as_f16
+#[no_mangle]
+pub fn i16_as_f16(a: i16) -> f16 {
+    // CHECK: sitofp i16 %{{.+}} to half
+    a as f16
+}
+
+// CHECK-LABEL: @i32_as_f16
+#[no_mangle]
+pub fn i32_as_f16(a: i32) -> f16 {
+    // CHECK: sitofp i32 %{{.+}} to half
+    a as f16
+}
+
+// CHECK-LABEL: @i64_as_f16
+#[no_mangle]
+pub fn i64_as_f16(a: i64) -> f16 {
+    // CHECK: sitofp i64 %{{.+}} to half
+    a as f16
+}
+
+// CHECK-LABEL: @i128_as_f16
+#[no_mangle]
+pub fn i128_as_f16(a: i128) -> f16 {
+    // CHECK: sitofp i128 %{{.+}} to half
+    a as f16
+}
diff --git a/tests/codegen-llvm/float_math.rs b/tests/codegen-llvm/float_math.rs
new file mode 100644
index 00000000000..9a1e0b4d2d0
--- /dev/null
+++ b/tests/codegen-llvm/float_math.rs
@@ -0,0 +1,87 @@
+//@ compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+use std::intrinsics::{
+    fadd_algebraic, fadd_fast, fdiv_algebraic, fdiv_fast, fmul_algebraic, fmul_fast,
+    frem_algebraic, frem_fast, fsub_algebraic, fsub_fast,
+};
+
+// CHECK-LABEL: @add
+#[no_mangle]
+pub fn add(x: f32, y: f32) -> f32 {
+    // CHECK: fadd float
+    // CHECK-NOT: fast
+    x + y
+}
+
+// CHECK-LABEL: @test_fadd_algebraic
+#[no_mangle]
+pub fn test_fadd_algebraic(x: f32, y: f32) -> f32 {
+    // CHECK: fadd reassoc nsz arcp contract float %x, %y
+    fadd_algebraic(x, y)
+}
+
+// CHECK-LABEL: @test_fsub_algebraic
+#[no_mangle]
+pub fn test_fsub_algebraic(x: f32, y: f32) -> f32 {
+    // CHECK: fsub reassoc nsz arcp contract float %x, %y
+    fsub_algebraic(x, y)
+}
+
+// CHECK-LABEL: @test_fmul_algebraic
+#[no_mangle]
+pub fn test_fmul_algebraic(x: f32, y: f32) -> f32 {
+    // CHECK: fmul reassoc nsz arcp contract float %x, %y
+    fmul_algebraic(x, y)
+}
+
+// CHECK-LABEL: @test_fdiv_algebraic
+#[no_mangle]
+pub fn test_fdiv_algebraic(x: f32, y: f32) -> f32 {
+    // CHECK: fdiv reassoc nsz arcp contract float %x, %y
+    fdiv_algebraic(x, y)
+}
+
+// CHECK-LABEL: @test_frem_algebraic
+#[no_mangle]
+pub fn test_frem_algebraic(x: f32, y: f32) -> f32 {
+    // CHECK: frem reassoc nsz arcp contract float %x, %y
+    frem_algebraic(x, y)
+}
+
+// CHECK-LABEL: @test_fadd_fast
+#[no_mangle]
+pub fn test_fadd_fast(x: f32, y: f32) -> f32 {
+    // CHECK: fadd fast float %x, %y
+    unsafe { fadd_fast(x, y) }
+}
+
+// CHECK-LABEL: @test_fsub_fast
+#[no_mangle]
+pub fn test_fsub_fast(x: f32, y: f32) -> f32 {
+    // CHECK: fsub fast float %x, %y
+    unsafe { fsub_fast(x, y) }
+}
+
+// CHECK-LABEL: @test_fmul_fast
+#[no_mangle]
+pub fn test_fmul_fast(x: f32, y: f32) -> f32 {
+    // CHECK: fmul fast float %x, %y
+    unsafe { fmul_fast(x, y) }
+}
+
+// CHECK-LABEL: @test_fdiv_fast
+#[no_mangle]
+pub fn test_fdiv_fast(x: f32, y: f32) -> f32 {
+    // CHECK: fdiv fast float %x, %y
+    unsafe { fdiv_fast(x, y) }
+}
+
+// CHECK-LABEL: @test_frem_fast
+#[no_mangle]
+pub fn test_frem_fast(x: f32, y: f32) -> f32 {
+    // CHECK: frem fast float %x, %y
+    unsafe { frem_fast(x, y) }
+}
diff --git a/tests/codegen-llvm/fn-impl-trait-self.rs b/tests/codegen-llvm/fn-impl-trait-self.rs
new file mode 100644
index 00000000000..5799d23b5a0
--- /dev/null
+++ b/tests/codegen-llvm/fn-impl-trait-self.rs
@@ -0,0 +1,17 @@
+//@ compile-flags: -g
+//@ ignore-wasi wasi codegens the main symbol differently
+//
+// CHECK-LABEL: @main
+// MSVC: {{.*}}DIDerivedType(tag: DW_TAG_pointer_type, name: "recursive_type$ (*)()",{{.*}}
+// NONMSVC: {{.*}}DIDerivedType(tag: DW_TAG_pointer_type, name: "fn() -> <recursive_type>",{{.*}}
+//
+// CHECK: {{.*}}DISubroutineType{{.*}}
+// CHECK: {{.*}}DIBasicType(name: "<recur_type>", size: {{32|64}}, encoding: DW_ATE_unsigned)
+
+pub fn foo() -> impl Copy {
+    foo
+}
+
+fn main() {
+    let my_res = foo();
+}
diff --git a/tests/codegen-llvm/fn-parameters-on-different-lines-debuginfo.rs b/tests/codegen-llvm/fn-parameters-on-different-lines-debuginfo.rs
new file mode 100644
index 00000000000..2097567f322
--- /dev/null
+++ b/tests/codegen-llvm/fn-parameters-on-different-lines-debuginfo.rs
@@ -0,0 +1,22 @@
+//! Make sure that line debuginfo of function parameters are correct even if
+//! they are not on the same line. Regression test for
+// <https://github.com/rust-lang/rust/issues/45010>.
+
+//@ compile-flags: -g -Copt-level=0
+
+#[rustfmt::skip] // Having parameters on different lines is crucial for this test.
+pub fn foo(
+    x_parameter_not_in_std: i32,
+    y_parameter_not_in_std: i32,
+) -> i32 {
+    x_parameter_not_in_std + y_parameter_not_in_std
+}
+
+fn main() {
+    foo(42, 43); // Ensure `wasm32-wasip1` keeps `foo()` (even if `-Copt-level=0`)
+}
+
+// CHECK: !DILocalVariable(name: "x_parameter_not_in_std", arg: 1,
+// CHECK-SAME: line: 9
+// CHECK: !DILocalVariable(name: "y_parameter_not_in_std", arg: 2,
+// CHECK-SAME: line: 10
diff --git a/tests/codegen-llvm/force-frame-pointers.rs b/tests/codegen-llvm/force-frame-pointers.rs
new file mode 100644
index 00000000000..88c918945d6
--- /dev/null
+++ b/tests/codegen-llvm/force-frame-pointers.rs
@@ -0,0 +1,18 @@
+//@ revisions: Always NonLeaf
+//@ [Always] compile-flags: -Cforce-frame-pointers=yes
+//@ [NonLeaf] compile-flags: -Cforce-frame-pointers=non-leaf
+//@ compile-flags: -Zunstable-options
+//@ compile-flags: -C no-prepopulate-passes -Copt-level=0
+//@ [NonLeaf] ignore-illumos
+//@ [NonLeaf] ignore-openbsd
+//@ [NonLeaf] ignore-x86
+//@ [NonLeaf] ignore-x86_64-apple-darwin
+//@ [NonLeaf] ignore-windows-gnu
+//@ [NonLeaf] ignore-thumb
+// result is platform-dependent based on platform's frame pointer settings
+
+#![crate_type = "lib"]
+
+// Always: attributes #{{.*}} "frame-pointer"="all"
+// NonLeaf: attributes #{{.*}} "frame-pointer"="non-leaf"
+pub fn foo() {}
diff --git a/tests/codegen-llvm/force-no-unwind-tables.rs b/tests/codegen-llvm/force-no-unwind-tables.rs
new file mode 100644
index 00000000000..1de5e0858e0
--- /dev/null
+++ b/tests/codegen-llvm/force-no-unwind-tables.rs
@@ -0,0 +1,11 @@
+//@ compile-flags: -C no-prepopulate-passes -C panic=abort -C force-unwind-tables=n
+//@ ignore-windows: unwind tables are required for panics on Windows
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: define{{.*}}void @foo
+// CHECK-NOT: attributes #{{.*}} uwtable
+#[no_mangle]
+fn foo() {
+    panic!();
+}
diff --git a/tests/codegen-llvm/force-unwind-tables.rs b/tests/codegen-llvm/force-unwind-tables.rs
new file mode 100644
index 00000000000..a2ef8a10454
--- /dev/null
+++ b/tests/codegen-llvm/force-unwind-tables.rs
@@ -0,0 +1,6 @@
+//@ compile-flags: -C no-prepopulate-passes -C force-unwind-tables=y -Copt-level=0
+
+#![crate_type = "lib"]
+
+// CHECK: attributes #{{.*}} uwtable
+pub fn foo() {}
diff --git a/tests/codegen-llvm/frame-pointer-cli-control.rs b/tests/codegen-llvm/frame-pointer-cli-control.rs
new file mode 100644
index 00000000000..a65dd132763
--- /dev/null
+++ b/tests/codegen-llvm/frame-pointer-cli-control.rs
@@ -0,0 +1,61 @@
+//@ add-core-stubs
+//@ compile-flags: --crate-type=rlib -Copt-level=0
+//@ revisions: force-on aarch64-apple aarch64-apple-on aarch64-apple-off
+//@ [force-on] compile-flags: -Cforce-frame-pointers=on
+//@ [aarch64-apple] needs-llvm-components: aarch64
+//@ [aarch64-apple] compile-flags: --target=aarch64-apple-darwin
+//@ [aarch64-apple-on] needs-llvm-components: aarch64
+//@ [aarch64-apple-on] compile-flags: --target=aarch64-apple-darwin -Cforce-frame-pointers=on
+//@ [aarch64-apple-off] needs-llvm-components: aarch64
+//@ [aarch64-apple-off] compile-flags: --target=aarch64-apple-darwin -Cforce-frame-pointers=off
+/*!
+
+Tests the extent to which frame pointers can be controlled by the CLI.
+The behavior of our frame pointer options, at present, is an irreversible ratchet, where
+a "weaker" option that allows omitting frame pointers may be overridden by the target demanding
+that all code (or all non-leaf code, more often) must be compiled with frame pointers.
+This was discussed on 2025-05-22 in the T-compiler meeting and accepted as an intentional change,
+ratifying the prior decisions by compiler contributors and reviewers as correct,
+though it was also acknowledged that the flag allows somewhat confusing inputs.
+
+We find aarch64-apple-darwin useful because of its icy-clear policy regarding frame pointers,
+e.g. <https://developer.apple.com/documentation/xcode/writing-arm64-code-for-apple-platforms> says:
+
+* The frame pointer register (x29) must always address a valid frame record. Some functions —
+  such as leaf functions or tail calls — may opt not to create an entry in this list.
+  As a result, stack traces are always meaningful, even without debug information.
+
+Many Rust fn, if externally visible, may be expected to follow target ABI by tools or asm code!
+This can make it a problem to generate ABI-incorrect code, which may mean "with frame pointers".
+For this and other reasons, `-Cforce-frame-pointers=off` cannot override the target definition.
+This can cause some confusion because it is "reverse polarity" relative to C compilers, which have
+commands like `-fomit-frame-pointer`, `-fomit-leaf-frame-pointer`, or `-fno-omit-frame-pointer`!
+
+Specific cases where platforms or tools rely on frame pointers for sound or correct unwinding:
+- illumos: <https://smartos.org/bugview/OS-7515>
+- aarch64-windows: <https://github.com/rust-lang/rust/issues/123686>
+- aarch64-linux: <https://github.com/rust-lang/rust/issues/123733>
+- dtrace (freebsd and openbsd): <https://github.com/rust-lang/rust/issues/97723>
+- openbsd: <https://github.com/rust-lang/rust/issues/43575>
+- i686-msvc <https://github.com/rust-lang/backtrace-rs/pull/584#issuecomment-1966177530>
+- i686-mingw: <https://github.com/rust-lang/rust/commit/3f1d3948d6d434b34dd47f132c126a6cb6b8a4ab>
+*/
+#![feature(no_core, lang_items)]
+#![no_core]
+
+extern crate minicore;
+
+// CHECK: i32 @peach{{.*}}[[PEACH_ATTRS:\#[0-9]+]] {
+#[no_mangle]
+pub fn peach(x: u32) -> u32 {
+    x
+}
+
+// CHECK: attributes [[PEACH_ATTRS]] = {
+// force-on-SAME: {{.*}}"frame-pointer"="all"
+// aarch64-apple-SAME: {{.*}}"frame-pointer"="non-leaf"
+// aarch64-apple-on-SAME: {{.*}}"frame-pointer"="all"
+//
+// yes, we are testing this doesn't do anything:
+// aarch64-apple-off-SAME: {{.*}}"frame-pointer"="non-leaf"
+// CHECK-SAME: }
diff --git a/tests/codegen-llvm/frame-pointer.rs b/tests/codegen-llvm/frame-pointer.rs
new file mode 100644
index 00000000000..23989653fa8
--- /dev/null
+++ b/tests/codegen-llvm/frame-pointer.rs
@@ -0,0 +1,35 @@
+//@ add-core-stubs
+//@ compile-flags: --crate-type=rlib -Copt-level=0
+//@ revisions: aarch64-apple aarch64-linux force x64-apple x64-linux
+//@ [aarch64-apple] needs-llvm-components: aarch64
+//@ [aarch64-apple] compile-flags: --target=aarch64-apple-darwin
+//@ [aarch64-linux] needs-llvm-components: aarch64
+//@ [aarch64-linux] compile-flags: --target=aarch64-unknown-linux-gnu
+//@ [force] needs-llvm-components: x86
+//@ [force] compile-flags: --target=x86_64-unknown-linux-gnu -Cforce-frame-pointers=yes
+//@ [x64-apple] needs-llvm-components: x86
+//@ [x64-apple] compile-flags: --target=x86_64-apple-darwin
+//@ [x64-linux] needs-llvm-components: x86
+//@ [x64-linux] compile-flags: --target=x86_64-unknown-linux-gnu
+
+#![feature(no_core, lang_items)]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+// CHECK: define i32 @peach{{.*}}[[PEACH_ATTRS:\#[0-9]+]] {
+#[no_mangle]
+pub fn peach(x: u32) -> u32 {
+    x
+}
+
+// CHECK: attributes [[PEACH_ATTRS]] = {
+// x64-linux-NOT: {{.*}}"frame-pointer"{{.*}}
+// x64-apple-SAME: {{.*}}"frame-pointer"="all"
+// force-SAME: {{.*}}"frame-pointer"="all"
+//
+// AAPCS64 demands frame pointers:
+// aarch64-linux-SAME: {{.*}}"frame-pointer"="non-leaf"
+// aarch64-apple-SAME: {{.*}}"frame-pointer"="non-leaf"
+// CHECK-SAME: }
diff --git a/tests/codegen-llvm/function-arguments-noopt.rs b/tests/codegen-llvm/function-arguments-noopt.rs
new file mode 100644
index 00000000000..c80f119696d
--- /dev/null
+++ b/tests/codegen-llvm/function-arguments-noopt.rs
@@ -0,0 +1,69 @@
+//@ compile-flags: -C opt-level=0 -C no-prepopulate-passes
+
+// This test checks that arguments/returns in opt-level=0 builds,
+// while lacking attributes used for optimization, still have ABI-affecting attributes.
+
+#![crate_type = "lib"]
+#![feature(rustc_attrs)]
+
+pub struct S {
+    _field: [i32; 8],
+}
+
+// CHECK: zeroext i1 @boolean(i1 zeroext %x)
+#[no_mangle]
+pub fn boolean(x: bool) -> bool {
+    x
+}
+
+// CHECK-LABEL: @boolean_call
+#[no_mangle]
+pub fn boolean_call(x: bool, f: fn(bool) -> bool) -> bool {
+    // CHECK: call zeroext i1 %f(i1 zeroext %x)
+    f(x)
+}
+
+// CHECK: align 4 ptr @borrow(ptr align 4 %x)
+#[no_mangle]
+pub fn borrow(x: &i32) -> &i32 {
+    x
+}
+
+// CHECK: align 4 ptr @borrow_mut(ptr align 4 %x)
+#[no_mangle]
+pub fn borrow_mut(x: &mut i32) -> &mut i32 {
+    x
+}
+
+// CHECK-LABEL: @borrow_call
+#[no_mangle]
+pub fn borrow_call(x: &i32, f: fn(&i32) -> &i32) -> &i32 {
+    // CHECK: call align 4 ptr %f(ptr align 4 %x)
+    f(x)
+}
+
+// CHECK: void @struct_(ptr sret([32 x i8]) align 4{{( %_0)?}}, ptr align 4 %x)
+#[no_mangle]
+pub fn struct_(x: S) -> S {
+    x
+}
+
+// CHECK-LABEL: @struct_call
+#[no_mangle]
+pub fn struct_call(x: S, f: fn(S) -> S) -> S {
+    // CHECK: call void %f(ptr sret([32 x i8]) align 4{{( %_0)?}}, ptr align 4 %{{.+}})
+    f(x)
+}
+
+// CHECK: { i1, i8 } @enum_(i1 zeroext %x.0, i8 %x.1)
+#[no_mangle]
+pub fn enum_(x: Option<u8>) -> Option<u8> {
+    x
+}
+
+// CHECK-LABEL: @enum_call
+#[no_mangle]
+pub fn enum_call(x: Option<u8>, f: fn(Option<u8>) -> Option<u8>) -> Option<u8> {
+    // CHECK: call { i1, i8 } %f(i1 zeroext %x.0, i8 %x.1)
+    f(x)
+}
diff --git a/tests/codegen-llvm/function-arguments.rs b/tests/codegen-llvm/function-arguments.rs
new file mode 100644
index 00000000000..c8cd8526ae5
--- /dev/null
+++ b/tests/codegen-llvm/function-arguments.rs
@@ -0,0 +1,278 @@
+//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes
+#![crate_type = "lib"]
+#![feature(rustc_attrs)]
+#![feature(allocator_api)]
+
+use std::marker::PhantomPinned;
+use std::mem::MaybeUninit;
+use std::num::NonZero;
+use std::ptr::NonNull;
+
+pub struct S {
+    _field: [i32; 8],
+}
+
+pub struct UnsafeInner {
+    _field: std::cell::UnsafeCell<i16>,
+}
+
+pub struct NotUnpin {
+    _field: i32,
+    _marker: PhantomPinned,
+}
+
+pub enum MyBool {
+    True,
+    False,
+}
+
+// CHECK: noundef zeroext i1 @boolean(i1 noundef zeroext %x)
+#[no_mangle]
+pub fn boolean(x: bool) -> bool {
+    x
+}
+
+// CHECK: i8 @maybeuninit_boolean(i8{{.*}} %x)
+#[no_mangle]
+pub fn maybeuninit_boolean(x: MaybeUninit<bool>) -> MaybeUninit<bool> {
+    x
+}
+
+// CHECK: noundef zeroext i1 @enum_bool(i1 noundef zeroext %x)
+#[no_mangle]
+pub fn enum_bool(x: MyBool) -> MyBool {
+    x
+}
+
+// CHECK: i8 @maybeuninit_enum_bool(i8{{.*}} %x)
+#[no_mangle]
+pub fn maybeuninit_enum_bool(x: MaybeUninit<MyBool>) -> MaybeUninit<MyBool> {
+    x
+}
+
+// CHECK: noundef{{( range\(i32 0, 1114112\))?}} i32 @char(i32{{.*}}{{( range\(i32 0, 1114112\))?}} %x)
+#[no_mangle]
+pub fn char(x: char) -> char {
+    x
+}
+
+// CHECK: i32 @maybeuninit_char(i32{{.*}} %x)
+#[no_mangle]
+pub fn maybeuninit_char(x: MaybeUninit<char>) -> MaybeUninit<char> {
+    x
+}
+
+// CHECK: noundef i64 @int(i64 noundef %x)
+#[no_mangle]
+pub fn int(x: u64) -> u64 {
+    x
+}
+
+// CHECK: noundef{{( range\(i64 1, 0\))?}} i64 @nonzero_int(i64 noundef{{( range\(i64 1, 0\))?}} %x)
+#[no_mangle]
+pub fn nonzero_int(x: NonZero<u64>) -> NonZero<u64> {
+    x
+}
+
+// CHECK: noundef i64 @option_nonzero_int(i64 noundef %x)
+#[no_mangle]
+pub fn option_nonzero_int(x: Option<NonZero<u64>>) -> Option<NonZero<u64>> {
+    x
+}
+
+// CHECK: @readonly_borrow(ptr noalias noundef readonly align 4 dereferenceable(4) %_1)
+// FIXME #25759 This should also have `nocapture`
+#[no_mangle]
+pub fn readonly_borrow(_: &i32) {}
+
+// CHECK: noundef align 4 dereferenceable(4) ptr @readonly_borrow_ret()
+#[no_mangle]
+pub fn readonly_borrow_ret() -> &'static i32 {
+    loop {}
+}
+
+// CHECK: @static_borrow(ptr noalias noundef readonly align 4 dereferenceable(4) %_1)
+// static borrow may be captured
+#[no_mangle]
+pub fn static_borrow(_: &'static i32) {}
+
+// CHECK: @named_borrow(ptr noalias noundef readonly align 4 dereferenceable(4) %_1)
+// borrow with named lifetime may be captured
+#[no_mangle]
+pub fn named_borrow<'r>(_: &'r i32) {}
+
+// CHECK: @unsafe_borrow(ptr noundef nonnull align 2 %_1)
+// unsafe interior means this isn't actually readonly and there may be aliases ...
+#[no_mangle]
+pub fn unsafe_borrow(_: &UnsafeInner) {}
+
+// CHECK: @mutable_unsafe_borrow(ptr noalias noundef align 2 dereferenceable(2) %_1)
+// ... unless this is a mutable borrow, those never alias
+#[no_mangle]
+pub fn mutable_unsafe_borrow(_: &mut UnsafeInner) {}
+
+// CHECK: @mutable_borrow(ptr noalias noundef align 4 dereferenceable(4) %_1)
+// FIXME #25759 This should also have `nocapture`
+#[no_mangle]
+pub fn mutable_borrow(_: &mut i32) {}
+
+// CHECK: noundef align 4 dereferenceable(4) ptr @mutable_borrow_ret()
+#[no_mangle]
+pub fn mutable_borrow_ret() -> &'static mut i32 {
+    loop {}
+}
+
+#[no_mangle]
+// CHECK: @mutable_notunpin_borrow(ptr noundef nonnull align 4 %_1)
+// This one is *not* `noalias` because it might be self-referential.
+// It is also not `dereferenceable` due to
+// <https://github.com/rust-lang/unsafe-code-guidelines/issues/381>.
+pub fn mutable_notunpin_borrow(_: &mut NotUnpin) {}
+
+// CHECK: @notunpin_borrow(ptr noalias noundef readonly align 4 dereferenceable(4) %_1)
+// But `&NotUnpin` behaves perfectly normal.
+#[no_mangle]
+pub fn notunpin_borrow(_: &NotUnpin) {}
+
+// CHECK: @indirect_struct(ptr noalias{{( nocapture)?}} noundef readonly align 4{{( captures\(none\))?}} dereferenceable(32) %_1)
+#[no_mangle]
+pub fn indirect_struct(_: S) {}
+
+// CHECK: @borrowed_struct(ptr noalias noundef readonly align 4 dereferenceable(32) %_1)
+// FIXME #25759 This should also have `nocapture`
+#[no_mangle]
+pub fn borrowed_struct(_: &S) {}
+
+// CHECK: @option_borrow(ptr noalias noundef readonly align 4 dereferenceable_or_null(4) %_x)
+#[no_mangle]
+pub fn option_borrow(_x: Option<&i32>) {}
+
+// CHECK: @option_borrow_mut(ptr noalias noundef align 4 dereferenceable_or_null(4) %_x)
+#[no_mangle]
+pub fn option_borrow_mut(_x: Option<&mut i32>) {}
+
+// Function that must NOT have `dereferenceable` or `align`.
+#[rustc_layout_scalar_valid_range_start(16)]
+pub struct RestrictedAddress(&'static i16);
+enum E {
+    A(RestrictedAddress),
+    B,
+    C,
+}
+// If the `nonnull` ever goes missing, you might have to tweak the
+// scalar_valid_range on `RestrictedAddress` to get it back. You
+// might even have to add a `rustc_layout_scalar_valid_range_end`.
+// CHECK: @nonnull_and_nondereferenceable(ptr noundef nonnull %_x)
+#[no_mangle]
+pub fn nonnull_and_nondereferenceable(_x: E) {}
+
+// CHECK: @raw_struct(ptr noundef %_1)
+#[no_mangle]
+pub fn raw_struct(_: *const S) {}
+
+// CHECK: @raw_option_nonnull_struct(ptr noundef %_1)
+#[no_mangle]
+pub fn raw_option_nonnull_struct(_: Option<NonNull<S>>) {}
+
+// `Box` can get deallocated during execution of the function, so it should
+// not get `dereferenceable`.
+// CHECK: noundef nonnull align 4 ptr @_box(ptr noalias noundef nonnull align 4 %x)
+#[no_mangle]
+pub fn _box(x: Box<i32>) -> Box<i32> {
+    x
+}
+
+// With a custom allocator, it should *not* have `noalias`. (See
+// <https://github.com/rust-lang/miri/issues/3341> for why.) The second argument is the allocator,
+// which is a reference here that still carries `noalias` as usual.
+// CHECK: @_box_custom(ptr noundef nonnull align 4 %x.0, ptr noalias noundef nonnull readonly align 1 %x.1)
+#[no_mangle]
+pub fn _box_custom(x: Box<i32, &std::alloc::Global>) {
+    drop(x)
+}
+
+// CHECK: noundef nonnull align 4 ptr @notunpin_box(ptr noundef nonnull align 4 %x)
+#[no_mangle]
+pub fn notunpin_box(x: Box<NotUnpin>) -> Box<NotUnpin> {
+    x
+}
+
+// CHECK: @struct_return(ptr{{( dead_on_unwind)?}} noalias{{( nocapture)?}} noundef{{( writable)?}} sret([32 x i8]) align 4{{( captures\(none\))?}} dereferenceable(32){{( %_0)?}})
+#[no_mangle]
+pub fn struct_return() -> S {
+    S { _field: [0, 0, 0, 0, 0, 0, 0, 0] }
+}
+
+// Hack to get the correct size for the length part in slices
+// CHECK: @helper([[USIZE:i[0-9]+]] noundef %_1)
+#[no_mangle]
+pub fn helper(_: usize) {}
+
+// CHECK: @slice(ptr noalias noundef nonnull readonly align 1 %_1.0, [[USIZE]] noundef %_1.1)
+// FIXME #25759 This should also have `nocapture`
+#[no_mangle]
+pub fn slice(_: &[u8]) {}
+
+// CHECK: @mutable_slice(ptr noalias noundef nonnull align 1 %_1.0, [[USIZE]] noundef %_1.1)
+// FIXME #25759 This should also have `nocapture`
+#[no_mangle]
+pub fn mutable_slice(_: &mut [u8]) {}
+
+// CHECK: @unsafe_slice(ptr noundef nonnull align 2 %_1.0, [[USIZE]] noundef %_1.1)
+// unsafe interior means this isn't actually readonly and there may be aliases ...
+#[no_mangle]
+pub fn unsafe_slice(_: &[UnsafeInner]) {}
+
+// CHECK: @raw_slice(ptr noundef %_1.0, [[USIZE]] noundef %_1.1)
+#[no_mangle]
+pub fn raw_slice(_: *const [u8]) {}
+
+// CHECK: @str(ptr noalias noundef nonnull readonly align 1 %_1.0, [[USIZE]] noundef %_1.1)
+// FIXME #25759 This should also have `nocapture`
+#[no_mangle]
+pub fn str(_: &[u8]) {}
+
+// CHECK: @trait_borrow(ptr noundef nonnull align 1 %_1.0, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}) %_1.1)
+// FIXME #25759 This should also have `nocapture`
+#[no_mangle]
+pub fn trait_borrow(_: &dyn Drop) {}
+
+// CHECK: @option_trait_borrow(ptr noundef align 1 %x.0, ptr %x.1)
+#[no_mangle]
+pub fn option_trait_borrow(x: Option<&dyn Drop>) {}
+
+// CHECK: @option_trait_borrow_mut(ptr noundef align 1 %x.0, ptr %x.1)
+#[no_mangle]
+pub fn option_trait_borrow_mut(x: Option<&mut dyn Drop>) {}
+
+// CHECK: @trait_raw(ptr noundef %_1.0, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}) %_1.1)
+#[no_mangle]
+pub fn trait_raw(_: *const dyn Drop) {}
+
+// CHECK: @trait_box(ptr noalias noundef nonnull align 1{{( %0)?}}, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}){{( %1)?}})
+#[no_mangle]
+pub fn trait_box(_: Box<dyn Drop + Unpin>) {}
+
+// CHECK: { ptr, ptr } @trait_option(ptr noalias noundef align 1 %x.0, ptr %x.1)
+#[no_mangle]
+pub fn trait_option(x: Option<Box<dyn Drop + Unpin>>) -> Option<Box<dyn Drop + Unpin>> {
+    x
+}
+
+// CHECK: { ptr, [[USIZE]] } @return_slice(ptr noalias noundef nonnull readonly align 2 %x.0, [[USIZE]] noundef %x.1)
+#[no_mangle]
+pub fn return_slice(x: &[u16]) -> &[u16] {
+    x
+}
+
+// CHECK: { i16, i16 } @enum_id_1(i16 noundef{{( range\(i16 0, 3\))?}} %x.0, i16 %x.1)
+#[no_mangle]
+pub fn enum_id_1(x: Option<Result<u16, u16>>) -> Option<Result<u16, u16>> {
+    x
+}
+
+// CHECK: { i1, i8 } @enum_id_2(i1 noundef zeroext %x.0, i8 %x.1)
+#[no_mangle]
+pub fn enum_id_2(x: Option<u8>) -> Option<u8> {
+    x
+}
diff --git a/tests/codegen-llvm/function-return.rs b/tests/codegen-llvm/function-return.rs
new file mode 100644
index 00000000000..4127f516038
--- /dev/null
+++ b/tests/codegen-llvm/function-return.rs
@@ -0,0 +1,35 @@
+// Test that the `fn_ret_thunk_extern` function attribute is (not) emitted when
+// the `-Zfunction-return={keep,thunk-extern}` flag is (not) set.
+
+//@ add-core-stubs
+//@ revisions: unset keep thunk-extern keep-thunk-extern thunk-extern-keep
+//@ needs-llvm-components: x86
+//@ compile-flags: --target x86_64-unknown-linux-gnu
+//@ [keep] compile-flags: -Zfunction-return=keep
+//@ [thunk-extern] compile-flags: -Zfunction-return=thunk-extern
+//@ [keep-thunk-extern] compile-flags: -Zfunction-return=keep -Zfunction-return=thunk-extern
+//@ [thunk-extern-keep] compile-flags: -Zfunction-return=thunk-extern -Zfunction-return=keep
+
+#![crate_type = "lib"]
+#![feature(no_core, lang_items)]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+#[no_mangle]
+pub fn foo() {
+    // CHECK: @foo() unnamed_addr #0
+
+    // unset-NOT: fn_ret_thunk_extern
+    // keep-NOT: fn_ret_thunk_extern
+    // thunk-extern: attributes #0 = { {{.*}}fn_ret_thunk_extern{{.*}} }
+    // keep-thunk-extern: attributes #0 = { {{.*}}fn_ret_thunk_extern{{.*}} }
+    // thunk-extern-keep-NOT: fn_ret_thunk_extern
+}
+
+// unset-NOT: !{{[0-9]+}} = !{i32 4, !"function_return_thunk_extern", i32 1}
+// keep-NOT: !{{[0-9]+}} = !{i32 4, !"function_return_thunk_extern", i32 1}
+// thunk-extern: !{{[0-9]+}} = !{i32 4, !"function_return_thunk_extern", i32 1}
+// keep-thunk-extern: !{{[0-9]+}} = !{i32 4, !"function_return_thunk_extern", i32 1}
+// thunk-extern-keep-NOT: !{{[0-9]+}} = !{i32 4, !"function_return_thunk_extern", i32 1}
diff --git a/tests/codegen-llvm/gdb_debug_script_load.rs b/tests/codegen-llvm/gdb_debug_script_load.rs
new file mode 100644
index 00000000000..3e92eba10b1
--- /dev/null
+++ b/tests/codegen-llvm/gdb_debug_script_load.rs
@@ -0,0 +1,37 @@
+//
+//@ ignore-windows
+//@ ignore-apple
+//@ ignore-wasm
+//@ ignore-emscripten
+
+//@ compile-flags: -g -C no-prepopulate-passes -Cpanic=abort
+
+#![feature(lang_items)]
+#![no_std]
+
+#[panic_handler]
+fn panic_handler(_: &core::panic::PanicInfo) -> ! {
+    loop {}
+}
+
+#[no_mangle]
+extern "C" fn rust_eh_personality() {
+    loop {}
+}
+
+// Needs rustc to generate `main` as that's where the magic load is inserted.
+// IOW, we cannot write this test with `#![no_main]`.
+// CHECK-LABEL: @main
+// CHECK: load volatile i8, {{.+}} @__rustc_debug_gdb_scripts_section__
+
+#[lang = "start"]
+fn lang_start<T: 'static>(
+    _main: fn() -> T,
+    _argc: isize,
+    _argv: *const *const u8,
+    _sigpipe: u8,
+) -> isize {
+    return 0;
+}
+
+fn main() {}
diff --git a/tests/codegen-llvm/generic-debug.rs b/tests/codegen-llvm/generic-debug.rs
new file mode 100644
index 00000000000..0ad0b074657
--- /dev/null
+++ b/tests/codegen-llvm/generic-debug.rs
@@ -0,0 +1,17 @@
+//@ ignore-wasi wasi codegens the main symbol differently
+
+//@ compile-flags: -g -C no-prepopulate-passes
+
+// CHECK-LABEL: @main
+// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_structure_type,{{.*}}name: "Generic<i32>",{{.*}}
+// CHECK: {{.*}}DITemplateTypeParameter{{.*}}name: "Type",{{.*}}
+
+#![allow(dead_code)]
+#![allow(unused_variables)]
+#![allow(unused_assignments)]
+
+pub struct Generic<Type>(Type);
+
+fn main() {
+    let generic = Generic(10);
+}
diff --git a/tests/codegen-llvm/gep-index.rs b/tests/codegen-llvm/gep-index.rs
new file mode 100644
index 00000000000..bfb2511af87
--- /dev/null
+++ b/tests/codegen-llvm/gep-index.rs
@@ -0,0 +1,37 @@
+//! Check that index and offset use the same getelementptr format.
+
+//@ revisions: NO-OPT OPT
+//@[NO-OPT] compile-flags: -Copt-level=0
+//@[OPT] compile-flags: -Copt-level=1
+
+#![crate_type = "lib"]
+
+struct Foo(i32, i32);
+
+// CHECK-LABEL: @index_on_struct(
+#[no_mangle]
+fn index_on_struct(a: &[Foo], index: usize) -> &Foo {
+    // CHECK: getelementptr inbounds{{( nuw)?}} %Foo, ptr %a.0, {{i64|i32}} %index
+    &a[index]
+}
+
+// CHECK-LABEL: @offset_on_struct(
+#[no_mangle]
+fn offset_on_struct(a: *const Foo, index: usize) -> *const Foo {
+    // CHECK: getelementptr inbounds{{( nuw)?}} %Foo, ptr %a, {{i64|i32}} %index
+    unsafe { a.add(index) }
+}
+
+// CHECK-LABEL: @index_on_i32(
+#[no_mangle]
+fn index_on_i32(a: &[i32], index: usize) -> &i32 {
+    // CHECK: getelementptr inbounds{{( nuw)?}} i32, ptr %a.0, {{i64|i32}} %index
+    &a[index]
+}
+
+// CHECK-LABEL: @offset_on_i32(
+#[no_mangle]
+fn offset_on_i32(a: *const i32, index: usize) -> *const i32 {
+    // CHECK: getelementptr inbounds{{( nuw)?}} i32, ptr %a, {{i64|i32}} %index
+    unsafe { a.add(index) }
+}
diff --git a/tests/codegen-llvm/gpu-kernel-abi.rs b/tests/codegen-llvm/gpu-kernel-abi.rs
new file mode 100644
index 00000000000..8ac376d9338
--- /dev/null
+++ b/tests/codegen-llvm/gpu-kernel-abi.rs
@@ -0,0 +1,15 @@
+// Checks that the gpu-kernel calling convention correctly translates to LLVM calling conventions.
+
+//@ add-core-stubs
+//@ revisions: nvptx
+//@ [nvptx] compile-flags: --crate-type=rlib --target=nvptx64-nvidia-cuda
+//@ [nvptx] needs-llvm-components: nvptx
+#![feature(no_core, lang_items, abi_gpu_kernel)]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+// nvptx: define ptx_kernel void @fun(i32
+#[no_mangle]
+pub extern "gpu-kernel" fn fun(_: i32) {}
diff --git a/tests/codegen-llvm/gpu_offload/gpu_host.rs b/tests/codegen-llvm/gpu_offload/gpu_host.rs
new file mode 100644
index 00000000000..513e27426bc
--- /dev/null
+++ b/tests/codegen-llvm/gpu_offload/gpu_host.rs
@@ -0,0 +1,80 @@
+//@ compile-flags: -Zoffload=Enable -Zunstable-options -C opt-level=3  -Clto=fat
+//@ no-prefer-dynamic
+//@ needs-enzyme
+
+// This test is verifying that we generate __tgt_target_data_*_mapper before and after a call to the
+// kernel_1. Better documentation to what each global or variable means is available in the gpu
+// offlaod code, or the LLVM offload documentation. This code does not launch any GPU kernels yet,
+// and will be rewritten once a proper offload frontend has landed.
+//
+// We currently only handle memory transfer for specific calls to functions named `kernel_{num}`,
+// when inside of a function called main. This, too, is a temporary workaround for not having a
+// frontend.
+
+#![no_main]
+
+#[unsafe(no_mangle)]
+fn main() {
+    let mut x = [3.0; 256];
+    kernel_1(&mut x);
+    core::hint::black_box(&x);
+}
+
+// CHECK: %struct.__tgt_offload_entry = type { i64, i16, i16, i32, ptr, ptr, i64, i64, ptr }
+// CHECK: %struct.__tgt_kernel_arguments = type { i32, i32, ptr, ptr, ptr, ptr, ptr, ptr, i64, i64, [3 x i32], [3 x i32], i32 }
+// CHECK: %struct.ident_t = type { i32, i32, i32, i32, ptr }
+// CHECK: %struct.__tgt_bin_desc = type { i32, ptr, ptr, ptr }
+
+// CHECK: @.offload_sizes.1 = private unnamed_addr constant [1 x i64] [i64 1024]
+// CHECK: @.offload_maptypes.1 = private unnamed_addr constant [1 x i64] [i64 3]
+// CHECK: @.kernel_1.region_id = weak unnamed_addr constant i8 0
+// CHECK: @.offloading.entry_name.1 = internal unnamed_addr constant [9 x i8] c"kernel_1\00", section ".llvm.rodata.offloading", align 1
+// CHECK: @.offloading.entry.kernel_1 = weak constant %struct.__tgt_offload_entry { i64 0, i16 1, i16 1, i32 0, ptr @.kernel_1.region_id, ptr @.offloading.entry_name.1, i64 0, i64 0, ptr null }, section ".omp_offloading_entries", align 1
+// CHECK: @my_struct_global2 = external global %struct.__tgt_kernel_arguments
+// CHECK: @0 = private unnamed_addr constant [23 x i8] c";unknown;unknown;0;0;;\00", align 1
+// CHECK: @1 = private unnamed_addr constant %struct.ident_t { i32 0, i32 2, i32 0, i32 22, ptr @0 }, align 8
+
+// CHECK:  Function Attrs:
+// CHECK-NEXT: define{{( dso_local)?}} void @main()
+// CHECK-NEXT: start:
+// CHECK-NEXT:   %0 = alloca [8 x i8], align 8
+// CHECK-NEXT:   %x = alloca [1024 x i8], align 16
+// CHECK-NEXT:   %EmptyDesc = alloca %struct.__tgt_bin_desc, align 8
+// CHECK-NEXT:   %.offload_baseptrs = alloca [1 x ptr], align 8
+// CHECK-NEXT:   %.offload_ptrs = alloca [1 x ptr], align 8
+// CHECK-NEXT:   %.offload_sizes = alloca [1 x i64], align 8
+// CHECK-NEXT:   %x.addr = alloca ptr, align 8
+// CHECK-NEXT:   store ptr %x, ptr %x.addr, align 8
+// CHECK-NEXT:   %1 = load ptr, ptr %x.addr, align 8
+// CHECK-NEXT:   %2 = getelementptr inbounds float, ptr %1, i32 0
+// CHECK:        call void @llvm.memset.p0.i64(ptr align 8 %EmptyDesc, i8 0, i64 32, i1 false)
+// CHECK-NEXT:   call void @__tgt_register_lib(ptr %EmptyDesc)
+// CHECK-NEXT:   call void @__tgt_init_all_rtls()
+// CHECK-NEXT:   %3 = getelementptr inbounds [1 x ptr], ptr %.offload_baseptrs, i32 0, i32 0
+// CHECK-NEXT:   store ptr %1, ptr %3, align 8
+// CHECK-NEXT:   %4 = getelementptr inbounds [1 x ptr], ptr %.offload_ptrs, i32 0, i32 0
+// CHECK-NEXT:   store ptr %2, ptr %4, align 8
+// CHECK-NEXT:   %5 = getelementptr inbounds [1 x i64], ptr %.offload_sizes, i32 0, i32 0
+// CHECK-NEXT:   store i64 1024, ptr %5, align 8
+// CHECK-NEXT:   %6 = getelementptr inbounds [1 x ptr], ptr %.offload_baseptrs, i32 0, i32 0
+// CHECK-NEXT:   %7 = getelementptr inbounds [1 x ptr], ptr %.offload_ptrs, i32 0, i32 0
+// CHECK-NEXT:   %8 = getelementptr inbounds [1 x i64], ptr %.offload_sizes, i32 0, i32 0
+// CHECK-NEXT:   call void @__tgt_target_data_begin_mapper(ptr @1, i64 -1, i32 1, ptr %6, ptr %7, ptr %8, ptr @.offload_maptypes.1, ptr null, ptr null)
+// CHECK-NEXT:   call void @kernel_1(ptr noalias noundef nonnull align 4 dereferenceable(1024) %x)
+// CHECK-NEXT:   %9 = getelementptr inbounds [1 x ptr], ptr %.offload_baseptrs, i32 0, i32 0
+// CHECK-NEXT:   %10 = getelementptr inbounds [1 x ptr], ptr %.offload_ptrs, i32 0, i32 0
+// CHECK-NEXT:   %11 = getelementptr inbounds [1 x i64], ptr %.offload_sizes, i32 0, i32 0
+// CHECK-NEXT:   call void @__tgt_target_data_end_mapper(ptr @1, i64 -1, i32 1, ptr %9, ptr %10, ptr %11, ptr @.offload_maptypes.1, ptr null, ptr null)
+// CHECK-NEXT:   call void @__tgt_unregister_lib(ptr %EmptyDesc)
+// CHECK:        store ptr %x, ptr %0, align 8
+// CHECK-NEXT:   call void asm sideeffect "", "r,~{memory}"(ptr nonnull %0)
+// CHECK:        ret void
+// CHECK-NEXT: }
+
+#[unsafe(no_mangle)]
+#[inline(never)]
+pub fn kernel_1(x: &mut [f32; 256]) {
+    for i in 0..256 {
+        x[i] = 21.0;
+    }
+}
diff --git a/tests/codegen-llvm/hint/cold_path.rs b/tests/codegen-llvm/hint/cold_path.rs
new file mode 100644
index 00000000000..149abe474f6
--- /dev/null
+++ b/tests/codegen-llvm/hint/cold_path.rs
@@ -0,0 +1,54 @@
+//@ compile-flags: -Copt-level=3
+#![crate_type = "lib"]
+#![feature(cold_path)]
+
+use std::hint::cold_path;
+
+#[inline(never)]
+#[no_mangle]
+pub fn path_a() {
+    println!("path a");
+}
+
+#[inline(never)]
+#[no_mangle]
+pub fn path_b() {
+    println!("path b");
+}
+
+#[no_mangle]
+pub fn test1(x: bool) {
+    if x {
+        path_a();
+    } else {
+        cold_path();
+        path_b();
+    }
+
+    // CHECK-LABEL: @test1(
+    // CHECK: br i1 %x, label %bb1, label %bb2, !prof ![[NUM:[0-9]+]]
+    // CHECK: bb2:
+    // CHECK: path_b
+    // CHECK: bb1:
+    // CHECK: path_a
+}
+
+#[no_mangle]
+pub fn test2(x: i32) {
+    match x > 0 {
+        true => path_a(),
+        false => {
+            cold_path();
+            path_b()
+        }
+    }
+
+    // CHECK-LABEL: @test2(
+    // CHECK: br i1 %_2, label %bb2, label %bb1, !prof ![[NUM]]
+    // CHECK: bb1:
+    // CHECK: path_b
+    // CHECK: bb2:
+    // CHECK: path_a
+}
+
+// CHECK: ![[NUM]] = !{!"branch_weights", {{(!"expected", )?}}i32 2000, i32 1}
diff --git a/tests/codegen-llvm/hint/likely.rs b/tests/codegen-llvm/hint/likely.rs
new file mode 100644
index 00000000000..75f9e7aae36
--- /dev/null
+++ b/tests/codegen-llvm/hint/likely.rs
@@ -0,0 +1,81 @@
+//@ compile-flags: -Copt-level=3
+#![crate_type = "lib"]
+#![feature(likely_unlikely)]
+
+use std::hint::likely;
+
+#[inline(never)]
+#[no_mangle]
+pub fn path_a() {
+    println!("path a");
+}
+
+#[inline(never)]
+#[no_mangle]
+pub fn path_b() {
+    println!("path b");
+}
+
+#[no_mangle]
+pub fn test1(x: bool) {
+    if likely(x) {
+        path_a();
+    } else {
+        path_b();
+    }
+
+    // CHECK-LABEL: @test1(
+    // CHECK: br i1 %x, label %bb2, label %bb3, !prof ![[NUM:[0-9]+]]
+    // CHECK: bb3:
+    // CHECK: path_b
+    // CHECK: bb2:
+    // CHECK: path_a
+}
+
+#[no_mangle]
+pub fn test2(x: i32) {
+    match likely(x > 0) {
+        true => path_a(),
+        false => path_b(),
+    }
+
+    // CHECK-LABEL: @test2(
+    // CHECK: br i1 %_2, label %bb2, label %bb3, !prof ![[NUM]]
+    // CHECK: bb3:
+    // CHECK: path_b
+    // CHECK: bb2:
+    // CHECK: path_a
+}
+
+#[no_mangle]
+pub fn test3(x: i8) {
+    match likely(x < 7) {
+        true => path_a(),
+        _ => path_b(),
+    }
+
+    // CHECK-LABEL: @test3(
+    // CHECK: br i1 %_2, label %bb2, label %bb3, !prof ![[NUM]]
+    // CHECK: bb3:
+    // CHECK: path_b
+    // CHECK: bb2:
+    // CHECK: path_a
+}
+
+#[no_mangle]
+pub fn test4(x: u64) {
+    match likely(x != 33) {
+        false => path_a(),
+        _ => path_b(),
+    }
+
+    // CHECK-LABEL: @test4(
+    // CHECK: br i1 %0, label %bb3, label %bb2, !prof ![[NUM2:[0-9]+]]
+    // CHECK: bb3:
+    // CHECK: path_a
+    // CHECK: bb2:
+    // CHECK: path_b
+}
+
+// CHECK: ![[NUM]] = !{!"branch_weights", {{(!"expected", )?}}i32 2000, i32 1}
+// CHECK: ![[NUM2]] = !{!"branch_weights", {{(!"expected", )?}}i32 1, i32 2000}
diff --git a/tests/codegen-llvm/hint/unlikely.rs b/tests/codegen-llvm/hint/unlikely.rs
new file mode 100644
index 00000000000..248b1e2537e
--- /dev/null
+++ b/tests/codegen-llvm/hint/unlikely.rs
@@ -0,0 +1,80 @@
+//@ compile-flags: -Copt-level=3
+#![crate_type = "lib"]
+#![feature(likely_unlikely)]
+
+use std::hint::unlikely;
+
+#[inline(never)]
+#[no_mangle]
+pub fn path_a() {
+    println!("path a");
+}
+
+#[inline(never)]
+#[no_mangle]
+pub fn path_b() {
+    println!("path b");
+}
+
+#[no_mangle]
+pub fn test1(x: bool) {
+    if unlikely(x) {
+        path_a();
+    } else {
+        path_b();
+    }
+
+    // CHECK-LABEL: @test1(
+    // CHECK: br i1 %x, label %bb2, label %bb4, !prof ![[NUM:[0-9]+]]
+    // CHECK: bb4:
+    // CHECK: path_b
+    // CHECK: bb2:
+    // CHECK: path_a
+}
+
+#[no_mangle]
+pub fn test2(x: i32) {
+    match unlikely(x > 0) {
+        true => path_a(),
+        false => path_b(),
+    }
+
+    // CHECK-LABEL: @test2(
+    // CHECK: br i1 %_2, label %bb2, label %bb4, !prof ![[NUM]]
+    // CHECK: bb4:
+    // CHECK: path_b
+    // CHECK: bb2:
+    // CHECK: path_a
+}
+
+#[no_mangle]
+pub fn test3(x: i8) {
+    match unlikely(x < 7) {
+        true => path_a(),
+        _ => path_b(),
+    }
+
+    // CHECK-LABEL: @test3(
+    // CHECK: br i1 %_2, label %bb2, label %bb4, !prof ![[NUM]]
+    // CHECK: bb4:
+    // CHECK: path_b
+    // CHECK: bb2:
+    // CHECK: path_a
+}
+
+#[no_mangle]
+pub fn test4(x: u64) {
+    match unlikely(x != 33) {
+        false => path_a(),
+        _ => path_b(),
+    }
+
+    // CHECK-LABEL: @test4(
+    // CHECK: br i1 %0, label %bb4, label %bb2, !prof ![[NUM2:[0-9]+]]
+    // CHECK: bb4:
+    // CHECK: path_a
+    // CHECK: bb2:
+    // CHECK: path_b
+}
+
+// CHECK: ![[NUM]] = !{!"branch_weights", {{(!"expected", )?}}i32 1, i32 2000}
diff --git a/tests/codegen-llvm/i128-wasm32-callconv.rs b/tests/codegen-llvm/i128-wasm32-callconv.rs
new file mode 100644
index 00000000000..9d73d270ef3
--- /dev/null
+++ b/tests/codegen-llvm/i128-wasm32-callconv.rs
@@ -0,0 +1,49 @@
+//! Verify that Rust implements the expected calling convention for `i128`/`u128`.
+
+//@ add-core-stubs
+//@ compile-flags: -Copt-level=3 --target wasm32-wasip1
+//@ needs-llvm-components: webassembly
+
+#![crate_type = "lib"]
+#![no_std]
+#![no_core]
+#![feature(no_core, lang_items)]
+
+extern crate minicore;
+
+extern "C" {
+    fn extern_call(arg0: i128);
+    fn extern_ret() -> i128;
+}
+
+#[no_mangle]
+pub extern "C" fn pass(_arg0: u32, arg1: i128) {
+    // CHECK-LABEL: @pass(
+    // an i128 is passed via registers
+    // CHECK-SAME: i128 noundef %arg1
+    // CHECK: call void @extern_call
+    unsafe { extern_call(arg1) };
+}
+
+// Check that we produce the correct return ABI
+#[no_mangle]
+pub extern "C" fn ret(_arg0: u32, arg1: i128) -> i128 {
+    // CHECK-LABEL: @ret(
+    // but an i128 is returned via the stack
+    // CHECK-SAME: sret
+    // CHECK: store i128 %arg1
+    // CHECK-NEXT: ret void
+    arg1
+}
+
+// Check that we consume the correct return ABI
+#[no_mangle]
+pub extern "C" fn forward(dst: *mut i128) {
+    // CHECK-LABEL: @forward
+    // CHECK-SAME: ptr{{.*}} %dst)
+    // without optimizatons, an intermediate alloca is used
+    // CHECK: call void @extern_ret
+    // CHECK: store i128
+    // CHECK: ret void
+    unsafe { *dst = extern_ret() };
+}
diff --git a/tests/codegen-llvm/i128-x86-align.rs b/tests/codegen-llvm/i128-x86-align.rs
new file mode 100644
index 00000000000..75802b0c505
--- /dev/null
+++ b/tests/codegen-llvm/i128-x86-align.rs
@@ -0,0 +1,105 @@
+//@ only-x86_64
+//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes --crate-type=lib
+
+// On LLVM 17 and earlier LLVM's own data layout specifies that i128 has 8 byte alignment,
+// while rustc wants it to have 16 byte alignment. This test checks that we handle this
+// correctly.
+
+// CHECK: %ScalarPair = type { i32, [3 x i32], i128 }
+
+#![feature(core_intrinsics)]
+
+#[repr(C)]
+#[derive(Clone, Copy)]
+pub struct ScalarPair {
+    a: i32,
+    b: i128,
+}
+
+#[no_mangle]
+pub fn load(x: &ScalarPair) -> ScalarPair {
+    // CHECK-LABEL: @load(
+    // CHECK-SAME: sret([32 x i8]) align 16
+    // CHECK-SAME: dereferenceable(32) %_0,
+    // CHECK-SAME: align 16
+    // CHECK-SAME: dereferenceable(32) %x
+    // CHECK:      [[A:%.*]] = load i32, ptr %x, align 16
+    // CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr %x, i64 16
+    // CHECK-NEXT: [[B:%.*]] = load i128, ptr [[GEP]], align 16
+    // CHECK-NEXT: store i32 [[A]], ptr %_0, align 16
+    // CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr %_0, i64 16
+    // CHECK-NEXT: store i128 [[B]], ptr [[GEP]], align 16
+    // CHECK-NEXT: ret void
+    *x
+}
+
+#[no_mangle]
+pub fn store(x: &mut ScalarPair) {
+    // CHECK-LABEL: @store(
+    // CHECK-SAME: align 16
+    // CHECK-SAME: dereferenceable(32) %x
+    // CHECK:      store i32 1, ptr %x, align 16
+    // CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr %x, i64 16
+    // CHECK-NEXT: store i128 2, ptr [[GEP]], align 16
+    *x = ScalarPair { a: 1, b: 2 };
+}
+
+#[no_mangle]
+pub fn alloca() {
+    // CHECK-LABEL: @alloca(
+    // CHECK:      [[X:%.*]] = alloca [32 x i8], align 16
+    // CHECK:      store i32 1, ptr %x, align 16
+    // CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr %x, i64 16
+    // CHECK-NEXT: store i128 2, ptr [[GEP]], align 16
+    let mut x = ScalarPair { a: 1, b: 2 };
+    store(&mut x);
+}
+
+#[no_mangle]
+pub fn load_volatile(x: &ScalarPair) -> ScalarPair {
+    // CHECK-LABEL: @load_volatile(
+    // CHECK-SAME: sret([32 x i8]) align 16
+    // CHECK-SAME: dereferenceable(32) %_0,
+    // CHECK-SAME: align 16
+    // CHECK-SAME: dereferenceable(32) %x
+    // CHECK:      [[LOAD:%.*]] = load volatile %ScalarPair, ptr %x, align 16
+    // CHECK-NEXT: store %ScalarPair [[LOAD]], ptr %_0, align 16
+    // CHECK-NEXT: ret void
+    unsafe { std::intrinsics::volatile_load(x) }
+}
+
+#[no_mangle]
+pub fn transmute(x: ScalarPair) -> (std::mem::MaybeUninit<i128>, i128) {
+    // CHECK-LABEL: @transmute(
+    // CHECK-SAME:  sret([32 x i8]) align 16
+    // CHECK-SAME:  dereferenceable(32) %_0,
+    // CHECK-SAME:  i32 noundef %x.0, i128 noundef %x.1
+    // CHECK:       store i32 %x.0, ptr %_0, align 16
+    // CHECK-NEXT:  [[GEP:%.*]] = getelementptr inbounds i8, ptr %_0, i64 16
+    // CHECK-NEXT:  store i128 %x.1, ptr [[GEP]], align 16
+    // CHECK-NEXT:  ret void
+    unsafe { std::mem::transmute(x) }
+}
+
+#[repr(C)]
+#[derive(Clone, Copy)]
+pub struct Struct {
+    a: i32,
+    b: i32,
+    c: i128,
+}
+
+#[no_mangle]
+pub fn store_struct(x: &mut Struct) {
+    // CHECK-LABEL: @store_struct(
+    // CHECK-SAME: align 16
+    // CHECK-SAME: dereferenceable(32) %x
+    // CHECK:      [[TMP:%.*]] = alloca [32 x i8], align 16
+    // CHECK:      store i32 1, ptr [[TMP]], align 16
+    // CHECK-NEXT: [[GEP1:%.*]] = getelementptr inbounds i8, ptr [[TMP]], i64 4
+    // CHECK-NEXT: store i32 2, ptr [[GEP1]], align 4
+    // CHECK-NEXT: [[GEP2:%.*]] = getelementptr inbounds i8, ptr [[TMP]], i64 16
+    // CHECK-NEXT: store i128 3, ptr [[GEP2]], align 16
+    // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 16 %x, ptr align 16 [[TMP]], i64 32, i1 false)
+    *x = Struct { a: 1, b: 2, c: 3 };
+}
diff --git a/tests/codegen-llvm/i128-x86-callconv.rs b/tests/codegen-llvm/i128-x86-callconv.rs
new file mode 100644
index 00000000000..41c30c09c1a
--- /dev/null
+++ b/tests/codegen-llvm/i128-x86-callconv.rs
@@ -0,0 +1,87 @@
+//! Verify that Rust implements the expected calling convention for `i128`/`u128`.
+
+// Eliminate intermediate instructions during `nop` tests
+//@ compile-flags: -Copt-level=1
+
+//@ add-core-stubs
+//@ revisions: MSVC MINGW softfloat
+//@ [MSVC] needs-llvm-components: x86
+//@ [MSVC] compile-flags: --target x86_64-pc-windows-msvc
+// Use `WIN` as a common prefix for MSVC and MINGW but *not* the softfloat test.
+//@ [MSVC] filecheck-flags: --check-prefix=WIN
+//@ [MINGW] needs-llvm-components: x86
+//@ [MINGW] compile-flags: --target x86_64-pc-windows-gnu
+//@ [MINGW] filecheck-flags: --check-prefix=WIN
+// The `x86_64-unknown-uefi` target also uses the Windows calling convention,
+// but does not have SSE registers available.
+//@ [softfloat] needs-llvm-components: x86
+//@ [softfloat] compile-flags: --target x86_64-unknown-uefi
+
+#![crate_type = "lib"]
+#![no_std]
+#![no_core]
+#![feature(no_core, lang_items)]
+
+extern crate minicore;
+
+extern "C" {
+    fn extern_call(arg0: i128);
+    fn extern_ret() -> i128;
+}
+
+#[no_mangle]
+pub extern "C" fn pass(_arg0: u32, arg1: i128) {
+    // CHECK-LABEL: @pass(
+    // i128 is passed indirectly on Windows. It should load the pointer to the stack and pass
+    // a pointer to that allocation. The softfloat ABI works the same.
+    // CHECK-SAME: %_arg0, ptr{{.*}} %arg1)
+    // CHECK: [[PASS:%[_0-9]+]] = alloca [16 x i8], align 16
+    // CHECK: [[LOADED:%[_0-9]+]] = load i128, ptr %arg1
+    // CHECK: store i128 [[LOADED]], ptr [[PASS]]
+    // CHECK: call void @extern_call
+    unsafe { extern_call(arg1) };
+}
+
+// Check that we produce the correct return ABI
+#[no_mangle]
+pub extern "C" fn ret(_arg0: u32, arg1: i128) -> i128 {
+    // WIN-LABEL: @ret(
+    // i128 is returned in xmm0 on Windows
+    // FIXME(#134288): This may change for the `-msvc` targets in the future.
+    // WIN-SAME: i32{{.*}} %_arg0, ptr{{.*}} %arg1)
+    // WIN: [[LOADED:%[_0-9]+]] = load <16 x i8>, ptr %arg1
+    // WIN-NEXT: ret <16 x i8> [[LOADED]]
+    // The softfloat ABI returns this indirectly.
+    // softfloat-LABEL: i128 @ret(i32{{.*}} %_arg0, ptr{{.*}} %arg1)
+    arg1
+}
+
+// Check that we consume the correct return ABI
+#[no_mangle]
+pub extern "C" fn forward(dst: *mut i128) {
+    // CHECK-LABEL: @forward
+    // WIN-SAME: ptr{{.*}} %dst)
+    // WIN: [[RETURNED:%[_0-9]+]] = tail call <16 x i8> @extern_ret()
+    // WIN: store <16 x i8> [[RETURNED]], ptr %dst
+    // WIN: ret void
+    // softfloat: [[RETURNED:%[_0-9]+]] = tail call {{.*}}i128 @extern_ret()
+    unsafe { *dst = extern_ret() };
+}
+
+#[repr(C)]
+struct RetAggregate {
+    a: i32,
+    b: i128,
+}
+
+#[no_mangle]
+pub extern "C" fn ret_aggregate(_arg0: u32, arg1: i128) -> RetAggregate {
+    // CHECK-LABEL: @ret_aggregate(
+    // Aggregates should also be returned indirectly
+    // CHECK-SAME: ptr{{.*}}sret([32 x i8]){{.*}}[[RET:%[_0-9]+]], i32{{.*}}%_arg0, ptr{{.*}}%arg1)
+    // CHECK: [[LOADED:%[_0-9]+]] = load i128, ptr %arg1
+    // CHECK: [[GEP:%[_0-9]+]] = getelementptr{{.*}}, ptr [[RET]]
+    // CHECK: store i128 [[LOADED]], ptr [[GEP]]
+    // CHECK: ret void
+    RetAggregate { a: 1, b: arg1 }
+}
diff --git a/tests/codegen-llvm/infallible-unwrap-in-opt-z.rs b/tests/codegen-llvm/infallible-unwrap-in-opt-z.rs
new file mode 100644
index 00000000000..c2297c58e77
--- /dev/null
+++ b/tests/codegen-llvm/infallible-unwrap-in-opt-z.rs
@@ -0,0 +1,26 @@
+//@ compile-flags: -C opt-level=z
+//@ edition: 2021
+
+#![crate_type = "lib"]
+
+// From <https://github.com/rust-lang/rust/issues/115463>
+
+// CHECK-LABEL: @read_up_to_8(
+#[no_mangle]
+pub fn read_up_to_8(buf: &[u8]) -> u64 {
+    // CHECK-NOT: unwrap_failed
+    if buf.len() < 4 {
+        // actual instance has more code.
+        return 0;
+    }
+    let lo = u32::from_le_bytes(buf[..4].try_into().unwrap()) as u64;
+    let hi = u32::from_le_bytes(buf[buf.len() - 4..][..4].try_into().unwrap()) as u64;
+    lo | (hi << 8 * (buf.len() as u64 - 4))
+}
+
+// CHECK-LABEL: @checking_unwrap_expectation(
+#[no_mangle]
+pub fn checking_unwrap_expectation(buf: &[u8]) -> &[u8; 4] {
+    // CHECK: call void @{{.*core6result13unwrap_failed}}
+    buf.try_into().unwrap()
+}
diff --git a/tests/codegen-llvm/inherit_overflow.rs b/tests/codegen-llvm/inherit_overflow.rs
new file mode 100644
index 00000000000..e4a5ef39fc5
--- /dev/null
+++ b/tests/codegen-llvm/inherit_overflow.rs
@@ -0,0 +1,14 @@
+//@ compile-flags: -Zmir-enable-passes=+Inline,+GVN --crate-type lib
+//@ revisions: ASSERT NOASSERT
+//@[ASSERT] compile-flags: -Coverflow-checks=on
+//@[NOASSERT] compile-flags: -Coverflow-checks=off
+
+// CHECK-LABEL: define{{.*}} @assertion
+// ASSERT: call void @{{.*4core9panicking11panic_const24panic_const_add_overflow}}
+// NOASSERT: ret i8 0
+#[no_mangle]
+pub fn assertion() -> u8 {
+    // Optimized MIR will replace this `CheckedBinaryOp` by `const (0, true)`.
+    // Verify that codegen does or does not emit the panic.
+    <u8 as std::ops::Add>::add(255, 1)
+}
diff --git a/tests/codegen-llvm/inline-always-works-always.rs b/tests/codegen-llvm/inline-always-works-always.rs
new file mode 100644
index 00000000000..07200fd9e37
--- /dev/null
+++ b/tests/codegen-llvm/inline-always-works-always.rs
@@ -0,0 +1,21 @@
+//@ revisions: NO-OPT SIZE-OPT SPEED-OPT
+//@[NO-OPT] compile-flags: -Copt-level=0
+//@[SIZE-OPT] compile-flags: -Copt-level=s
+//@[SPEED-OPT] compile-flags: -Copt-level=3
+
+#![crate_type = "rlib"]
+
+#[no_mangle]
+#[inline(always)]
+pub extern "C" fn callee() -> u32 {
+    4 + 4
+}
+
+// CHECK-LABEL: caller
+// SIZE-OPT: ret i32 8
+// SPEED-OPT: ret i32 8
+// NO-OPT: ret i32 8
+#[no_mangle]
+pub extern "C" fn caller() -> u32 {
+    callee()
+}
diff --git a/tests/codegen-llvm/inline-debuginfo.rs b/tests/codegen-llvm/inline-debuginfo.rs
new file mode 100644
index 00000000000..1e1c9037f5c
--- /dev/null
+++ b/tests/codegen-llvm/inline-debuginfo.rs
@@ -0,0 +1,17 @@
+#![crate_type = "rlib"]
+//@ compile-flags: -Copt-level=3 -g
+//
+
+#[no_mangle]
+#[inline(always)]
+pub extern "C" fn callee(x: u32) -> u32 {
+    x + 4
+}
+
+// CHECK-LABEL: caller
+// CHECK: dbg{{.}}value({{(metadata )?}}i32 %y, {{(metadata )?}}!{{.*}}, {{(metadata )?}}!DIExpression(DW_OP_constu, 3, DW_OP_minus, DW_OP_stack_value){{.*}} [[A:![0-9]+]]
+// CHECK: [[A]] = !DILocation(line: {{.*}}, scope: {{.*}}, inlinedAt: {{.*}})
+#[no_mangle]
+pub extern "C" fn caller(y: u32) -> u32 {
+    callee(y - 3)
+}
diff --git a/tests/codegen-llvm/inline-function-args-debug-info.rs b/tests/codegen-llvm/inline-function-args-debug-info.rs
new file mode 100644
index 00000000000..c31419cb914
--- /dev/null
+++ b/tests/codegen-llvm/inline-function-args-debug-info.rs
@@ -0,0 +1,23 @@
+// This test checks that debug information includes function argument indexes even if the function
+// gets inlined by MIR inlining. Without function argument indexes, `info args` in gdb won't show
+// arguments and their values for the current function.
+
+//@ compile-flags: -Zinline-mir=yes -Cdebuginfo=2
+//@ edition: 2021
+
+#![crate_type = "lib"]
+
+#[inline(never)]
+pub fn outer_function(x: usize, y: usize) -> usize {
+    inner_function(x, y) + 1
+}
+
+#[inline]
+fn inner_function(aaaa: usize, bbbb: usize) -> usize {
+    // CHECK: !DILocalVariable(name: "aaaa", arg: 1
+    // CHECK-SAME: line: 16
+    // CHECK-NOT: !DILexicalBlock(
+    // CHECK: !DILocalVariable(name: "bbbb", arg: 2
+    // CHECK-SAME: line: 16
+    aaaa + bbbb
+}
diff --git a/tests/codegen-llvm/inline-hint.rs b/tests/codegen-llvm/inline-hint.rs
new file mode 100644
index 00000000000..3d46885d5a2
--- /dev/null
+++ b/tests/codegen-llvm/inline-hint.rs
@@ -0,0 +1,31 @@
+// Checks that closures, constructors, and shims except
+// for a drop glue receive inline hint by default.
+//
+//@ compile-flags: -Cno-prepopulate-passes -Csymbol-mangling-version=v0 -Zinline-mir=no
+#![crate_type = "lib"]
+
+pub fn f() {
+    let a = A;
+    let b = (0i32, 1i32, 2i32, 3 as *const i32);
+    let c = || {};
+
+    a(String::new(), String::new());
+    b.clone();
+    c();
+}
+
+struct A(String, String);
+
+// CHECK:      ; core::ptr::drop_in_place::<inline_hint::A>
+// CHECK-NEXT: ; Function Attrs:
+// CHECK-NOT:  inlinehint
+// CHECK-SAME: {{$}}
+
+// CHECK:      ; <(i32, i32, i32, *const i{{16|32|64}}) as core::clone::Clone>::clone
+// CHECK-NEXT: ; Function Attrs: inlinehint
+
+// CHECK:      ; inline_hint::f::{closure#0}
+// CHECK-NEXT: ; Function Attrs: inlinehint
+
+// CHECK:      ; inline_hint::A
+// CHECK-NEXT: ; Function Attrs: inlinehint
diff --git a/tests/codegen-llvm/instrument-coverage/instrument-coverage-off.rs b/tests/codegen-llvm/instrument-coverage/instrument-coverage-off.rs
new file mode 100644
index 00000000000..e44d6c65874
--- /dev/null
+++ b/tests/codegen-llvm/instrument-coverage/instrument-coverage-off.rs
@@ -0,0 +1,21 @@
+// Test that `-Cinstrument-coverage=off` does not add coverage instrumentation to LLVM IR.
+
+//@ compile-flags: -Zno-profiler-runtime
+//@ revisions: n no off false_ zero
+//@ [n] compile-flags: -Cinstrument-coverage=n
+//@ [no] compile-flags: -Cinstrument-coverage=no
+//@ [off] compile-flags: -Cinstrument-coverage=off
+//@ [false_] compile-flags: -Cinstrument-coverage=false
+//@ [zero] compile-flags: -Cinstrument-coverage=0
+
+// CHECK-NOT: __llvm_profile_filename
+// CHECK-NOT: __llvm_coverage_mapping
+
+#![crate_type = "lib"]
+
+#[inline(never)]
+fn some_function() {}
+
+pub fn some_other_function() {
+    some_function();
+}
diff --git a/tests/codegen-llvm/instrument-coverage/instrument-coverage.rs b/tests/codegen-llvm/instrument-coverage/instrument-coverage.rs
new file mode 100644
index 00000000000..23d23651c72
--- /dev/null
+++ b/tests/codegen-llvm/instrument-coverage/instrument-coverage.rs
@@ -0,0 +1,22 @@
+// Test that `-Cinstrument-coverage` creates expected __llvm_profile_filename symbol in LLVM IR.
+
+//@ compile-flags: -Zno-profiler-runtime
+//@ revisions: default y yes on true_ all
+//@ [default] compile-flags: -Cinstrument-coverage
+//@ [y] compile-flags: -Cinstrument-coverage=y
+//@ [yes] compile-flags: -Cinstrument-coverage=yes
+//@ [on] compile-flags: -Cinstrument-coverage=on
+//@ [true_] compile-flags: -Cinstrument-coverage=true
+//@ [all] compile-flags: -Cinstrument-coverage=all
+
+// CHECK-DAG: @__llvm_coverage_mapping
+// CHECK-DAG: @__llvm_profile_filename = {{.*}}"default_%m_%p.profraw\00"{{.*}}
+
+#![crate_type = "lib"]
+
+#[inline(never)]
+fn some_function() {}
+
+pub fn some_other_function() {
+    some_function();
+}
diff --git a/tests/codegen-llvm/instrument-coverage/testprog.rs b/tests/codegen-llvm/instrument-coverage/testprog.rs
new file mode 100644
index 00000000000..9e918499d57
--- /dev/null
+++ b/tests/codegen-llvm/instrument-coverage/testprog.rs
@@ -0,0 +1,118 @@
+//@ edition: 2021
+//@ compile-flags: -Zno-profiler-runtime
+//@ compile-flags: -Cinstrument-coverage -Copt-level=0
+//@ revisions: LINUX DARWIN WIN
+
+//@ [LINUX] only-linux
+//@ [LINUX] filecheck-flags: -DINSTR_PROF_DATA=__llvm_prf_data
+//@ [LINUX] filecheck-flags: -DINSTR_PROF_NAME=__llvm_prf_names
+//@ [LINUX] filecheck-flags: -DINSTR_PROF_CNTS=__llvm_prf_cnts
+//@ [LINUX] filecheck-flags: -DINSTR_PROF_COVMAP=__llvm_covmap
+//@ [LINUX] filecheck-flags: -DINSTR_PROF_COVFUN=__llvm_covfun
+//@ [LINUX] filecheck-flags: '-DCOMDAT_IF_SUPPORTED=, comdat'
+
+//@ [DARWIN] only-apple
+//@ [DARWIN] filecheck-flags: -DINSTR_PROF_DATA=__DATA,__llvm_prf_data,regular,live_support
+//@ [DARWIN] filecheck-flags: -DINSTR_PROF_NAME=__DATA,__llvm_prf_names
+//@ [DARWIN] filecheck-flags: -DINSTR_PROF_CNTS=__DATA,__llvm_prf_cnts
+//@ [DARWIN] filecheck-flags: -DINSTR_PROF_COVMAP=__LLVM_COV,__llvm_covmap
+//@ [DARWIN] filecheck-flags: -DINSTR_PROF_COVFUN=__LLVM_COV,__llvm_covfun
+//@ [DARWIN] filecheck-flags: -DCOMDAT_IF_SUPPORTED=
+
+//@ [WIN] only-windows
+//@ [WIN] filecheck-flags: -DINSTR_PROF_DATA=.lprfd$M
+//@ [WIN] filecheck-flags: -DINSTR_PROF_NAME=.lprfn$M
+//@ [WIN] filecheck-flags: -DINSTR_PROF_CNTS=.lprfc$M
+//@ [WIN] filecheck-flags: -DINSTR_PROF_COVMAP=.lcovmap$M
+//@ [WIN] filecheck-flags: -DINSTR_PROF_COVFUN=.lcovfun$M
+//@ [WIN] filecheck-flags: '-DCOMDAT_IF_SUPPORTED=, comdat'
+
+// ignore-tidy-linelength
+
+pub fn will_be_called() -> &'static str {
+    let val = "called";
+    println!("{}", val);
+    val
+}
+
+pub fn will_not_be_called() -> bool {
+    println!("should not have been called");
+    false
+}
+
+pub fn print<T>(left: &str, value: T, right: &str)
+where
+    T: std::fmt::Display,
+{
+    println!("{}{}{}", left, value, right);
+}
+
+pub fn wrap_with<F, T>(inner: T, should_wrap: bool, wrapper: F)
+where
+    F: FnOnce(&T),
+{
+    if should_wrap {
+        wrapper(&inner)
+    }
+}
+
+fn main() {
+    let less = 1;
+    let more = 100;
+
+    if less < more {
+        wrap_with(will_be_called(), less < more, |inner| print(" ***", inner, "*** "));
+        wrap_with(will_be_called(), more < less, |inner| print(" ***", inner, "*** "));
+    } else {
+        wrap_with(will_not_be_called(), true, |inner| print("wrapped result is: ", inner, ""));
+    }
+}
+
+// Check for metadata, variables, declarations, and function definitions injected
+// into LLVM IR when compiling with -Cinstrument-coverage.
+
+// WIN:          $__llvm_profile_runtime_user = comdat any
+
+// CHECK-DAG:    @__llvm_coverage_mapping = private constant {{.*}}, section "[[INSTR_PROF_COVMAP]]", align 8
+
+// CHECK-DAG:    @__covrec_{{[A-F0-9]+}}u = linkonce_odr hidden constant {{.*}}, section "[[INSTR_PROF_COVFUN]]"[[COMDAT_IF_SUPPORTED]], align 8
+
+// WIN:          @__llvm_profile_runtime = external{{.*}}global i32
+
+// CHECK:        @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called = {{private|internal}} global
+// CHECK-SAME:   section "[[INSTR_PROF_CNTS]]"{{.*}}, align 8
+
+// CHECK:        @__profd__R{{[a-zA-Z0-9_]+}}testprog14will_be_called = {{private|internal}} global
+// CHECK-SAME:   @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called
+// CHECK-SAME:   section "[[INSTR_PROF_DATA]]"{{.*}}, align 8
+
+// CHECK:        @__profc__R{{[a-zA-Z0-9_]+}}testprog4main = {{private|internal}} global
+// CHECK-SAME:   section "[[INSTR_PROF_CNTS]]"{{.*}}, align 8
+
+// CHECK:        @__profd__R{{[a-zA-Z0-9_]+}}testprog4main = {{private|internal}} global
+// CHECK-SAME:   @__profc__R{{[a-zA-Z0-9_]+}}testprog4main
+// CHECK-SAME:   section "[[INSTR_PROF_DATA]]"{{.*}}, align 8
+
+// CHECK:        @__llvm_prf_nm = private constant
+// CHECK-SAME:   section "[[INSTR_PROF_NAME]]", align 1
+
+// CHECK:        @llvm.used = appending global
+// CHECK-SAME:   @__llvm_coverage_mapping
+// CHECK-SAME:   @__llvm_prf_nm
+// CHECK-SAME:   section "llvm.metadata"
+
+// CHECK:        define internal { {{.*}} } @_R{{[a-zA-Z0-9_]+}}testprog14will_be_called() unnamed_addr #{{[0-9]+}} {
+// CHECK-NEXT:   start:
+// CHECK-NOT:    define internal
+// CHECK:        atomicrmw add ptr
+// CHECK-SAME:   @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called,
+
+// CHECK:        declare void @llvm.instrprof.increment(ptr, i64, i32, i32) #[[LLVM_INSTRPROF_INCREMENT_ATTR:[0-9]+]]
+
+// WIN:          define linkonce_odr hidden i32 @__llvm_profile_runtime_user() #[[LLVM_PROFILE_RUNTIME_USER_ATTR:[0-9]+]] comdat {
+// WIN-NEXT:     %1 = load i32, ptr @__llvm_profile_runtime
+// WIN-NEXT:     ret i32 %1
+// WIN-NEXT:     }
+
+// CHECK:        attributes #[[LLVM_INSTRPROF_INCREMENT_ATTR]] = { nounwind }
+// WIN:          attributes #[[LLVM_PROFILE_RUNTIME_USER_ATTR]] = { noinline }
diff --git a/tests/codegen-llvm/instrument-mcount.rs b/tests/codegen-llvm/instrument-mcount.rs
new file mode 100644
index 00000000000..8c97535d4a8
--- /dev/null
+++ b/tests/codegen-llvm/instrument-mcount.rs
@@ -0,0 +1,7 @@
+//
+//@ compile-flags: -Z instrument-mcount -Copt-level=0
+
+#![crate_type = "lib"]
+
+// CHECK: attributes #{{.*}} "frame-pointer"="all" "instrument-function-entry-inlined"="{{.*}}mcount{{.*}}"
+pub fn foo() {}
diff --git a/tests/codegen-llvm/instrument-xray/basic.rs b/tests/codegen-llvm/instrument-xray/basic.rs
new file mode 100644
index 00000000000..7aaebf41e36
--- /dev/null
+++ b/tests/codegen-llvm/instrument-xray/basic.rs
@@ -0,0 +1,9 @@
+// Checks that `-Z instrument-xray` produces expected instrumentation.
+//
+//@ needs-xray
+//@ compile-flags: -Z instrument-xray=always -Copt-level=0
+
+#![crate_type = "lib"]
+
+// CHECK: attributes #{{.*}} "function-instrument"="xray-always"
+pub fn function() {}
diff --git a/tests/codegen-llvm/instrument-xray/options-combine.rs b/tests/codegen-llvm/instrument-xray/options-combine.rs
new file mode 100644
index 00000000000..d1e3b78e6b2
--- /dev/null
+++ b/tests/codegen-llvm/instrument-xray/options-combine.rs
@@ -0,0 +1,12 @@
+// Checks that `-Z instrument-xray` options can be specified multiple times.
+//
+//@ needs-xray
+//@ compile-flags: -Z instrument-xray=skip-exit -Copt-level=0
+//@ compile-flags: -Z instrument-xray=instruction-threshold=123 -Copt-level=0
+//@ compile-flags: -Z instrument-xray=instruction-threshold=456 -Copt-level=0
+
+#![crate_type = "lib"]
+
+// CHECK:      attributes #{{.*}} "xray-instruction-threshold"="456" "xray-skip-exit"
+// CHECK-NOT:  attributes #{{.*}} "xray-instruction-threshold"="123"
+pub fn function() {}
diff --git a/tests/codegen-llvm/instrument-xray/options-override.rs b/tests/codegen-llvm/instrument-xray/options-override.rs
new file mode 100644
index 00000000000..428fb723edb
--- /dev/null
+++ b/tests/codegen-llvm/instrument-xray/options-override.rs
@@ -0,0 +1,11 @@
+// Checks that the last `-Z instrument-xray` option wins.
+//
+//@ needs-xray
+//@ compile-flags: -Z instrument-xray=always -Copt-level=0
+//@ compile-flags: -Z instrument-xray=never -Copt-level=0
+
+#![crate_type = "lib"]
+
+// CHECK:      attributes #{{.*}} "function-instrument"="xray-never"
+// CHECK-NOT:  attributes #{{.*}} "function-instrument"="xray-always"
+pub fn function() {}
diff --git a/tests/codegen-llvm/integer-cmp.rs b/tests/codegen-llvm/integer-cmp.rs
new file mode 100644
index 00000000000..812fa8e4a42
--- /dev/null
+++ b/tests/codegen-llvm/integer-cmp.rs
@@ -0,0 +1,62 @@
+// This is test for more optimal Ord implementation for integers.
+// See <https://github.com/rust-lang/rust/issues/63758> for more info.
+
+//@ revisions: llvm-pre-20 llvm-20
+//@ [llvm-20] min-llvm-version: 20
+//@ [llvm-pre-20] max-llvm-major-version: 19
+//@ compile-flags: -C opt-level=3 -Zmerge-functions=disabled
+
+#![crate_type = "lib"]
+
+use std::cmp::Ordering;
+
+// CHECK-LABEL: @cmp_signed
+#[no_mangle]
+pub fn cmp_signed(a: i64, b: i64) -> Ordering {
+    // llvm-20: call{{.*}} i8 @llvm.scmp.i8.i64
+    // llvm-pre-20: icmp slt
+    // llvm-pre-20: icmp ne
+    // llvm-pre-20: zext i1
+    // llvm-pre-20: select i1
+    a.cmp(&b)
+}
+
+// CHECK-LABEL: @cmp_unsigned
+#[no_mangle]
+pub fn cmp_unsigned(a: u32, b: u32) -> Ordering {
+    // llvm-20: call{{.*}} i8 @llvm.ucmp.i8.i32
+    // llvm-pre-20: icmp ult
+    // llvm-pre-20: icmp ne
+    // llvm-pre-20: zext i1
+    // llvm-pre-20: select i1
+    a.cmp(&b)
+}
+
+// CHECK-LABEL: @cmp_char
+#[no_mangle]
+pub fn cmp_char(a: char, b: char) -> Ordering {
+    // llvm-20: call{{.*}} i8 @llvm.ucmp.i8.i32
+    // llvm-pre-20: icmp ult
+    // llvm-pre-20: icmp ne
+    // llvm-pre-20: zext i1
+    // llvm-pre-20: select i1
+    a.cmp(&b)
+}
+
+// CHECK-LABEL: @cmp_tuple
+#[no_mangle]
+pub fn cmp_tuple(a: (i16, u16), b: (i16, u16)) -> Ordering {
+    // llvm-20-DAG: call{{.*}} i8 @llvm.ucmp.i8.i16
+    // llvm-20-DAG: call{{.*}} i8 @llvm.scmp.i8.i16
+    // llvm-20: ret i8
+    // llvm-pre-20: icmp slt
+    // llvm-pre-20: icmp ne
+    // llvm-pre-20: zext i1
+    // llvm-pre-20: select i1
+    // llvm-pre-20: icmp ult
+    // llvm-pre-20: icmp ne
+    // llvm-pre-20: zext i1
+    // llvm-pre-20: select i1
+    // llvm-pre-20: select i1
+    a.cmp(&b)
+}
diff --git a/tests/codegen-llvm/integer-overflow.rs b/tests/codegen-llvm/integer-overflow.rs
new file mode 100644
index 00000000000..80362247a86
--- /dev/null
+++ b/tests/codegen-llvm/integer-overflow.rs
@@ -0,0 +1,24 @@
+//@ compile-flags: -Copt-level=3 -C overflow-checks=on
+
+#![crate_type = "lib"]
+
+pub struct S1<'a> {
+    data: &'a [u8],
+    position: usize,
+}
+
+// CHECK-LABEL: @slice_no_index_order
+#[no_mangle]
+pub fn slice_no_index_order<'a>(s: &'a mut S1, n: usize) -> &'a [u8] {
+    // CHECK-NOT: slice_index_order_fail
+    let d = &s.data[s.position..s.position + n];
+    s.position += n;
+    return d;
+}
+
+// CHECK-LABEL: @test_check
+#[no_mangle]
+pub fn test_check<'a>(s: &'a mut S1, x: usize, y: usize) -> &'a [u8] {
+    // CHECK: slice_index_order_fail
+    &s.data[x..y]
+}
diff --git a/tests/codegen-llvm/internalize-closures.rs b/tests/codegen-llvm/internalize-closures.rs
new file mode 100644
index 00000000000..f226ea6faac
--- /dev/null
+++ b/tests/codegen-llvm/internalize-closures.rs
@@ -0,0 +1,13 @@
+//@ compile-flags: -C no-prepopulate-passes -Zmir-opt-level=0
+
+pub fn main() {
+    // We want to make sure that closures get 'internal' linkage instead of
+    // 'weak_odr' when they are not shared between codegen units
+    // FIXME(eddyb) `legacy` mangling uses `{{closure}}`, while `v0`
+    // uses `{closure#0}`, switch to the latter once `legacy` is gone.
+    // CHECK-LABEL: ; internalize_closures::main::{{.*}}closure
+    // CHECK-NEXT: ; Function Attrs:
+    // CHECK-NEXT: define internal
+    let c = |x: i32| x + 1;
+    let _ = c(1);
+}
diff --git a/tests/codegen-llvm/intrinsic-no-unnamed-attr.rs b/tests/codegen-llvm/intrinsic-no-unnamed-attr.rs
new file mode 100644
index 00000000000..4bec579831d
--- /dev/null
+++ b/tests/codegen-llvm/intrinsic-no-unnamed-attr.rs
@@ -0,0 +1,13 @@
+//@ compile-flags: -C no-prepopulate-passes
+
+#![feature(core_intrinsics)]
+
+use std::intrinsics::sqrtf32;
+
+// CHECK: @llvm.sqrt.f32(float) #{{[0-9]*}}
+
+fn main() {
+    unsafe {
+        sqrtf32(0.0f32);
+    }
+}
diff --git a/tests/codegen-llvm/intrinsics/aggregate-thin-pointer.rs b/tests/codegen-llvm/intrinsics/aggregate-thin-pointer.rs
new file mode 100644
index 00000000000..bd590ce9180
--- /dev/null
+++ b/tests/codegen-llvm/intrinsics/aggregate-thin-pointer.rs
@@ -0,0 +1,23 @@
+//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes -Z mir-enable-passes=-InstSimplify
+//@ only-64bit (so I don't need to worry about usize)
+
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+use std::intrinsics::aggregate_raw_ptr;
+
+// InstSimplify replaces these with casts if it can, which means they're almost
+// never seen in codegen, but PR#121571 found a way, so add a test for it.
+
+#[inline(never)]
+pub fn opaque(_p: &*const i32) {}
+
+// CHECK-LABEL: @thin_ptr_via_aggregate(
+#[no_mangle]
+pub unsafe fn thin_ptr_via_aggregate(p: *const ()) {
+    // CHECK: %mem = alloca
+    // CHECK: store ptr %p, ptr %mem
+    // CHECK: call {{.+}}aggregate_thin_pointer{{.+}} %mem)
+    let mem = aggregate_raw_ptr(p, ());
+    opaque(&mem);
+}
diff --git a/tests/codegen-llvm/intrinsics/carrying_mul_add.rs b/tests/codegen-llvm/intrinsics/carrying_mul_add.rs
new file mode 100644
index 00000000000..21fb49a3786
--- /dev/null
+++ b/tests/codegen-llvm/intrinsics/carrying_mul_add.rs
@@ -0,0 +1,136 @@
+//@ revisions: RAW OPT
+//@ compile-flags: -C opt-level=1
+//@[RAW] compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+#![feature(core_intrinsics_fallbacks)]
+
+// Note that LLVM seems to sometimes permute the order of arguments to mul and add,
+// so these tests don't check the arguments in the optimized revision.
+
+use std::intrinsics::{carrying_mul_add, fallback};
+
+// The fallbacks are emitted even when they're never used, but optimize out.
+
+// RAW: wide_mul_u128
+// OPT-NOT: wide_mul_u128
+
+// CHECK-LABEL: @cma_u8
+#[no_mangle]
+pub unsafe fn cma_u8(a: u8, b: u8, c: u8, d: u8) -> (u8, u8) {
+    // CHECK: [[A:%.+]] = zext i8 %a to i16
+    // CHECK: [[B:%.+]] = zext i8 %b to i16
+    // CHECK: [[C:%.+]] = zext i8 %c to i16
+    // CHECK: [[D:%.+]] = zext i8 %d to i16
+    // CHECK: [[AB:%.+]] = mul nuw i16
+    // RAW-SAME: [[A]], [[B]]
+    // CHECK: [[ABC:%.+]] = add nuw i16
+    // RAW-SAME: [[AB]], [[C]]
+    // CHECK: [[ABCD:%.+]] = add nuw i16
+    // RAW-SAME: [[ABC]], [[D]]
+    // CHECK: [[LOW:%.+]] = trunc i16 [[ABCD]] to i8
+    // CHECK: [[HIGHW:%.+]] = lshr i16 [[ABCD]], 8
+    // RAW: [[HIGH:%.+]] = trunc i16 [[HIGHW]] to i8
+    // OPT: [[HIGH:%.+]] = trunc nuw i16 [[HIGHW]] to i8
+    // CHECK: [[PAIR0:%.+]] = insertvalue { i8, i8 } poison, i8 [[LOW]], 0
+    // CHECK: [[PAIR1:%.+]] = insertvalue { i8, i8 } [[PAIR0]], i8 [[HIGH]], 1
+    // OPT: ret { i8, i8 } [[PAIR1]]
+    carrying_mul_add(a, b, c, d)
+}
+
+// CHECK-LABEL: @cma_u32
+#[no_mangle]
+pub unsafe fn cma_u32(a: u32, b: u32, c: u32, d: u32) -> (u32, u32) {
+    // CHECK: [[A:%.+]] = zext i32 %a to i64
+    // CHECK: [[B:%.+]] = zext i32 %b to i64
+    // CHECK: [[C:%.+]] = zext i32 %c to i64
+    // CHECK: [[D:%.+]] = zext i32 %d to i64
+    // CHECK: [[AB:%.+]] = mul nuw i64
+    // RAW-SAME: [[A]], [[B]]
+    // CHECK: [[ABC:%.+]] = add nuw i64
+    // RAW-SAME: [[AB]], [[C]]
+    // CHECK: [[ABCD:%.+]] = add nuw i64
+    // RAW-SAME: [[ABC]], [[D]]
+    // CHECK: [[LOW:%.+]] = trunc i64 [[ABCD]] to i32
+    // CHECK: [[HIGHW:%.+]] = lshr i64 [[ABCD]], 32
+    // RAW: [[HIGH:%.+]] = trunc i64 [[HIGHW]] to i32
+    // OPT: [[HIGH:%.+]] = trunc nuw i64 [[HIGHW]] to i32
+    // CHECK: [[PAIR0:%.+]] = insertvalue { i32, i32 } poison, i32 [[LOW]], 0
+    // CHECK: [[PAIR1:%.+]] = insertvalue { i32, i32 } [[PAIR0]], i32 [[HIGH]], 1
+    // OPT: ret { i32, i32 } [[PAIR1]]
+    carrying_mul_add(a, b, c, d)
+}
+
+// CHECK-LABEL: @cma_u128
+// CHECK-SAME: sret{{.+}}dereferenceable(32){{.+}}%_0,{{.+}}%a,{{.+}}%b,{{.+}}%c,{{.+}}%d
+#[no_mangle]
+pub unsafe fn cma_u128(a: u128, b: u128, c: u128, d: u128) -> (u128, u128) {
+    // CHECK: [[A:%.+]] = zext i128 %a to i256
+    // CHECK: [[B:%.+]] = zext i128 %b to i256
+    // CHECK: [[C:%.+]] = zext i128 %c to i256
+    // CHECK: [[D:%.+]] = zext i128 %d to i256
+    // CHECK: [[AB:%.+]] = mul nuw i256
+    // RAW-SAME: [[A]], [[B]]
+    // CHECK: [[ABC:%.+]] = add nuw i256
+    // RAW-SAME: [[AB]], [[C]]
+    // CHECK: [[ABCD:%.+]] = add nuw i256
+    // RAW-SAME: [[ABC]], [[D]]
+    // CHECK: [[LOW:%.+]] = trunc i256 [[ABCD]] to i128
+    // CHECK: [[HIGHW:%.+]] = lshr i256 [[ABCD]], 128
+    // RAW: [[HIGH:%.+]] = trunc i256 [[HIGHW]] to i128
+    // OPT: [[HIGH:%.+]] = trunc nuw i256 [[HIGHW]] to i128
+    // RAW: [[PAIR0:%.+]] = insertvalue { i128, i128 } poison, i128 [[LOW]], 0
+    // RAW: [[PAIR1:%.+]] = insertvalue { i128, i128 } [[PAIR0]], i128 [[HIGH]], 1
+    // OPT: store i128 [[LOW]], ptr %_0
+    // OPT: [[P1:%.+]] = getelementptr inbounds{{( nuw)?}} i8, ptr %_0, {{i32|i64}} 16
+    // OPT: store i128 [[HIGH]], ptr [[P1]]
+    // CHECK: ret void
+    carrying_mul_add(a, b, c, d)
+}
+
+// CHECK-LABEL: @cma_i128
+// CHECK-SAME: sret{{.+}}dereferenceable(32){{.+}}%_0,{{.+}}%a,{{.+}}%b,{{.+}}%c,{{.+}}%d
+#[no_mangle]
+pub unsafe fn cma_i128(a: i128, b: i128, c: i128, d: i128) -> (u128, i128) {
+    // CHECK: [[A:%.+]] = sext i128 %a to i256
+    // CHECK: [[B:%.+]] = sext i128 %b to i256
+    // CHECK: [[C:%.+]] = sext i128 %c to i256
+    // CHECK: [[D:%.+]] = sext i128 %d to i256
+    // CHECK: [[AB:%.+]] = mul nsw i256
+    // RAW-SAME: [[A]], [[B]]
+    // CHECK: [[ABC:%.+]] = add nsw i256
+    // RAW-SAME: [[AB]], [[C]]
+    // CHECK: [[ABCD:%.+]] = add nsw i256
+    // RAW-SAME: [[ABC]], [[D]]
+    // CHECK: [[LOW:%.+]] = trunc i256 [[ABCD]] to i128
+    // CHECK: [[HIGHW:%.+]] = lshr i256 [[ABCD]], 128
+    // RAW: [[HIGH:%.+]] = trunc i256 [[HIGHW]] to i128
+    // OPT: [[HIGH:%.+]] = trunc nuw i256 [[HIGHW]] to i128
+    // RAW: [[PAIR0:%.+]] = insertvalue { i128, i128 } poison, i128 [[LOW]], 0
+    // RAW: [[PAIR1:%.+]] = insertvalue { i128, i128 } [[PAIR0]], i128 [[HIGH]], 1
+    // OPT: store i128 [[LOW]], ptr %_0
+    // OPT: [[P1:%.+]] = getelementptr inbounds{{( nuw)?}} i8, ptr %_0, {{i32|i64}} 16
+    // OPT: store i128 [[HIGH]], ptr [[P1]]
+    // CHECK: ret void
+    carrying_mul_add(a, b, c, d)
+}
+
+// CHECK-LABEL: @fallback_cma_u32
+#[no_mangle]
+pub unsafe fn fallback_cma_u32(a: u32, b: u32, c: u32, d: u32) -> (u32, u32) {
+    // OPT-DAG: [[A:%.+]] = zext i32 %a to i64
+    // OPT-DAG: [[B:%.+]] = zext i32 %b to i64
+    // OPT-DAG: [[AB:%.+]] = mul nuw i64
+    // OPT-DAG: [[C:%.+]] = zext i32 %c to i64
+    // OPT-DAG: [[ABC:%.+]] = add nuw i64{{.+}}[[C]]
+    // OPT-DAG: [[D:%.+]] = zext i32 %d to i64
+    // OPT-DAG: [[ABCD:%.+]] = add nuw i64{{.+}}[[D]]
+    // OPT-DAG: [[LOW:%.+]] = trunc i64 [[ABCD]] to i32
+    // OPT-DAG: [[HIGHW:%.+]] = lshr i64 [[ABCD]], 32
+    // OPT-DAG: [[HIGH:%.+]] = trunc nuw i64 [[HIGHW]] to i32
+    // OPT-DAG: [[PAIR0:%.+]] = insertvalue { i32, i32 } poison, i32 [[LOW]], 0
+    // OPT-DAG: [[PAIR1:%.+]] = insertvalue { i32, i32 } [[PAIR0]], i32 [[HIGH]], 1
+    // OPT-DAG: ret { i32, i32 } [[PAIR1]]
+    fallback::CarryingMulAdd::carrying_mul_add(a, b, c, d)
+}
diff --git a/tests/codegen-llvm/intrinsics/cold_path.rs b/tests/codegen-llvm/intrinsics/cold_path.rs
new file mode 100644
index 00000000000..fd75324b671
--- /dev/null
+++ b/tests/codegen-llvm/intrinsics/cold_path.rs
@@ -0,0 +1,13 @@
+//@ compile-flags: -Copt-level=3
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+use std::intrinsics::cold_path;
+
+#[no_mangle]
+pub fn test_cold_path(x: bool) {
+    cold_path();
+}
+
+// CHECK-LABEL: @test_cold_path(
+// CHECK-NOT: cold_path
diff --git a/tests/codegen-llvm/intrinsics/cold_path2.rs b/tests/codegen-llvm/intrinsics/cold_path2.rs
new file mode 100644
index 00000000000..0891c878fd9
--- /dev/null
+++ b/tests/codegen-llvm/intrinsics/cold_path2.rs
@@ -0,0 +1,37 @@
+//@ compile-flags: -O
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+use std::intrinsics::cold_path;
+
+#[inline(never)]
+#[no_mangle]
+pub fn path_a() {
+    println!("path a");
+}
+
+#[inline(never)]
+#[no_mangle]
+pub fn path_b() {
+    println!("path b");
+}
+
+#[no_mangle]
+pub fn test(x: Option<bool>) {
+    if let Some(_) = x {
+        path_a();
+    } else {
+        cold_path();
+        path_b();
+    }
+
+    // CHECK-LABEL: void @test(i8{{.+}}%x)
+    // CHECK: %[[IS_NONE:.+]] = icmp eq i8 %x, 2
+    // CHECK: br i1 %[[IS_NONE]], label %bb2, label %bb1, !prof ![[NUM:[0-9]+]]
+    // CHECK: bb1:
+    // CHECK: path_a
+    // CHECK: bb2:
+    // CHECK: path_b
+}
+
+// CHECK: ![[NUM]] = !{!"branch_weights", {{(!"expected", )?}}i32 1, i32 2000}
diff --git a/tests/codegen-llvm/intrinsics/cold_path3.rs b/tests/codegen-llvm/intrinsics/cold_path3.rs
new file mode 100644
index 00000000000..bf3347de665
--- /dev/null
+++ b/tests/codegen-llvm/intrinsics/cold_path3.rs
@@ -0,0 +1,87 @@
+//@ compile-flags: -O
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+use std::intrinsics::cold_path;
+
+#[inline(never)]
+#[no_mangle]
+pub fn path_a() {
+    println!("path a");
+}
+
+#[inline(never)]
+#[no_mangle]
+pub fn path_b() {
+    println!("path b");
+}
+
+#[inline(never)]
+#[no_mangle]
+pub fn path_c() {
+    println!("path c");
+}
+
+#[inline(never)]
+#[no_mangle]
+pub fn path_d() {
+    println!("path d");
+}
+
+#[no_mangle]
+pub fn test(x: Option<u32>) {
+    match x {
+        Some(0) => path_a(),
+        Some(1) => {
+            cold_path();
+            path_b()
+        }
+        Some(2) => path_c(),
+        Some(3) => {
+            cold_path();
+            path_d()
+        }
+        _ => path_a(),
+    }
+
+    // CHECK-LABEL: @test(
+    // CHECK: switch i32 %1, label %bb1 [
+    // CHECK: i32 0, label %bb6
+    // CHECK: i32 1, label %bb5
+    // CHECK: i32 2, label %bb4
+    // CHECK: i32 3, label %bb3
+    // CHECK: ], !prof ![[NUM1:[0-9]+]]
+}
+
+#[no_mangle]
+pub fn test2(x: Option<u32>) {
+    match x {
+        Some(10) => path_a(),
+        Some(11) => {
+            cold_path();
+            path_b()
+        }
+        Some(12) => {
+            unsafe { core::intrinsics::unreachable() };
+            path_c()
+        }
+        Some(13) => {
+            cold_path();
+            path_d()
+        }
+        _ => {
+            cold_path();
+            path_a()
+        }
+    }
+
+    // CHECK-LABEL: @test2(
+    // CHECK: switch i32 %1, label %bb1 [
+    // CHECK: i32 10, label %bb5
+    // CHECK: i32 11, label %bb4
+    // CHECK: i32 13, label %bb3
+    // CHECK: ], !prof ![[NUM2:[0-9]+]]
+}
+
+// CHECK: ![[NUM1]] = !{!"branch_weights", i32 2000, i32 2000, i32 1, i32 2000, i32 1}
+// CHECK: ![[NUM2]] = !{!"branch_weights", i32 1, i32 2000, i32 1, i32 1}
diff --git a/tests/codegen-llvm/intrinsics/compare_bytes.rs b/tests/codegen-llvm/intrinsics/compare_bytes.rs
new file mode 100644
index 00000000000..3ab0e4e97e0
--- /dev/null
+++ b/tests/codegen-llvm/intrinsics/compare_bytes.rs
@@ -0,0 +1,34 @@
+//@ revisions: INT32 INT16
+//@ compile-flags: -Copt-level=3
+//@ [INT32] ignore-16bit
+//@ [INT16] only-16bit
+
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+use std::intrinsics::compare_bytes;
+
+#[no_mangle]
+// CHECK-LABEL: @bytes_cmp(
+pub unsafe fn bytes_cmp(a: *const u8, b: *const u8, n: usize) -> i32 {
+    // INT32: %[[TEMP:.+]] = tail call i32 @memcmp(ptr %a, ptr %b, {{i32|i64}} %n)
+    // INT32-NOT: sext
+    // INT32: ret i32 %[[TEMP]]
+
+    // INT16: %[[TEMP1:.+]] = tail call i16 @memcmp(ptr %a, ptr %b, i16 %n)
+    // INT16: %[[TEMP2:.+]] = sext i16 %[[TEMP1]] to i32
+    // INT16: ret i32 %[[TEMP2]]
+    compare_bytes(a, b, n)
+}
+
+// Ensure that, even though there's an `sext` emitted by the intrinsic,
+// that doesn't end up pessiming checks against zero.
+#[no_mangle]
+// CHECK-LABEL: @bytes_eq(
+pub unsafe fn bytes_eq(a: *const u8, b: *const u8, n: usize) -> bool {
+    // CHECK: call {{.+}} @{{bcmp|memcmp}}(ptr %a, ptr %b, {{i16|i32|i64}} %n)
+    // CHECK-NOT: sext
+    // INT32: icmp eq i32
+    // INT16: icmp eq i16
+    compare_bytes(a, b, n) == 0_i32
+}
diff --git a/tests/codegen-llvm/intrinsics/const_eval_select.rs b/tests/codegen-llvm/intrinsics/const_eval_select.rs
new file mode 100644
index 00000000000..baa985b00cd
--- /dev/null
+++ b/tests/codegen-llvm/intrinsics/const_eval_select.rs
@@ -0,0 +1,22 @@
+//@ compile-flags: -C no-prepopulate-passes -Copt-level=0
+
+#![crate_type = "lib"]
+#![feature(const_eval_select)]
+#![feature(core_intrinsics)]
+
+use std::intrinsics::const_eval_select;
+
+const fn foo(_: i32) -> i32 {
+    1
+}
+
+#[no_mangle]
+pub fn hi(n: i32) -> i32 {
+    n
+}
+
+#[no_mangle]
+pub unsafe fn hey() {
+    // CHECK: call i32 @hi(i32
+    const_eval_select((42,), foo, hi);
+}
diff --git a/tests/codegen-llvm/intrinsics/ctlz.rs b/tests/codegen-llvm/intrinsics/ctlz.rs
new file mode 100644
index 00000000000..0d54d21ce12
--- /dev/null
+++ b/tests/codegen-llvm/intrinsics/ctlz.rs
@@ -0,0 +1,56 @@
+//@ compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+use std::intrinsics::{ctlz, ctlz_nonzero};
+
+// CHECK-LABEL: @ctlz_u16
+#[no_mangle]
+pub unsafe fn ctlz_u16(x: u16) -> u32 {
+    // CHECK: %[[tmp:.*]] = call i16 @llvm.ctlz.i16(i16 %x, i1 false)
+    // CHECK: zext i16 %[[tmp]] to i32
+    ctlz(x)
+}
+
+// CHECK-LABEL: @ctlz_nzu16
+#[no_mangle]
+pub unsafe fn ctlz_nzu16(x: u16) -> u32 {
+    // CHECK: %[[tmp:.*]] = call i16 @llvm.ctlz.i16(i16 %x, i1 true)
+    // CHECK: zext i16 %[[tmp]] to i32
+    ctlz_nonzero(x)
+}
+
+// CHECK-LABEL: @ctlz_u32
+#[no_mangle]
+pub unsafe fn ctlz_u32(x: u32) -> u32 {
+    // CHECK: call i32 @llvm.ctlz.i32(i32 %x, i1 false)
+    // CHECK-NOT: zext
+    // CHECK-NOT: trunc
+    ctlz(x)
+}
+
+// CHECK-LABEL: @ctlz_nzu32
+#[no_mangle]
+pub unsafe fn ctlz_nzu32(x: u32) -> u32 {
+    // CHECK: call i32 @llvm.ctlz.i32(i32 %x, i1 true)
+    // CHECK-NOT: zext
+    // CHECK-NOT: trunc
+    ctlz_nonzero(x)
+}
+
+// CHECK-LABEL: @ctlz_u64
+#[no_mangle]
+pub unsafe fn ctlz_u64(x: u64) -> u32 {
+    // CHECK: %[[tmp:.*]] = call i64 @llvm.ctlz.i64(i64 %x, i1 false)
+    // CHECK: trunc i64 %[[tmp]] to i32
+    ctlz(x)
+}
+
+// CHECK-LABEL: @ctlz_nzu64
+#[no_mangle]
+pub unsafe fn ctlz_nzu64(x: u64) -> u32 {
+    // CHECK: %[[tmp:.*]] = call i64 @llvm.ctlz.i64(i64 %x, i1 true)
+    // CHECK: trunc i64 %[[tmp]] to i32
+    ctlz_nonzero(x)
+}
diff --git a/tests/codegen-llvm/intrinsics/ctpop.rs b/tests/codegen-llvm/intrinsics/ctpop.rs
new file mode 100644
index 00000000000..f4043325de9
--- /dev/null
+++ b/tests/codegen-llvm/intrinsics/ctpop.rs
@@ -0,0 +1,31 @@
+//@ compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+use std::intrinsics::ctpop;
+
+// CHECK-LABEL: @ctpop_u16
+#[no_mangle]
+pub unsafe fn ctpop_u16(x: u16) -> u32 {
+    // CHECK: %[[tmp:.*]] = call i16 @llvm.ctpop.i16(i16 %x)
+    // CHECK: zext i16 %[[tmp]] to i32
+    ctpop(x)
+}
+
+// CHECK-LABEL: @ctpop_u32
+#[no_mangle]
+pub unsafe fn ctpop_u32(x: u32) -> u32 {
+    // CHECK: call i32 @llvm.ctpop.i32(i32 %x)
+    // CHECK-NOT: zext
+    // CHECK-NOT: trunc
+    ctpop(x)
+}
+
+// CHECK-LABEL: @ctpop_u64
+#[no_mangle]
+pub unsafe fn ctpop_u64(x: u64) -> u32 {
+    // CHECK: %[[tmp:.*]] = call i64 @llvm.ctpop.i64(i64 %x)
+    // CHECK: trunc i64 %[[tmp]] to i32
+    ctpop(x)
+}
diff --git a/tests/codegen-llvm/intrinsics/disjoint_bitor.rs b/tests/codegen-llvm/intrinsics/disjoint_bitor.rs
new file mode 100644
index 00000000000..fc45439ee0b
--- /dev/null
+++ b/tests/codegen-llvm/intrinsics/disjoint_bitor.rs
@@ -0,0 +1,30 @@
+//@ compile-flags: -C no-prepopulate-passes -Z mir-opt-level=0
+
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+use std::intrinsics::disjoint_bitor;
+
+// CHECK-LABEL: @disjoint_bitor_signed
+#[no_mangle]
+pub unsafe fn disjoint_bitor_signed(x: i32, y: i32) -> i32 {
+    // CHECK: or disjoint i32 %x, %y
+    disjoint_bitor(x, y)
+}
+
+// CHECK-LABEL: @disjoint_bitor_unsigned
+#[no_mangle]
+pub unsafe fn disjoint_bitor_unsigned(x: u64, y: u64) -> u64 {
+    // CHECK: or disjoint i64 %x, %y
+    disjoint_bitor(x, y)
+}
+
+// CHECK-LABEL: @disjoint_bitor_literal
+#[no_mangle]
+pub unsafe fn disjoint_bitor_literal() -> u8 {
+    // This is a separate check because even without any passes,
+    // LLVM will fold so it's not an instruction, which can assert in LLVM.
+
+    // CHECK: store i8 3
+    disjoint_bitor(1, 2)
+}
diff --git a/tests/codegen-llvm/intrinsics/exact_div.rs b/tests/codegen-llvm/intrinsics/exact_div.rs
new file mode 100644
index 00000000000..dc625ba7fe4
--- /dev/null
+++ b/tests/codegen-llvm/intrinsics/exact_div.rs
@@ -0,0 +1,20 @@
+//@ compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+use std::intrinsics::exact_div;
+
+// CHECK-LABEL: @exact_sdiv
+#[no_mangle]
+pub unsafe fn exact_sdiv(x: i32, y: i32) -> i32 {
+    // CHECK: sdiv exact
+    exact_div(x, y)
+}
+
+// CHECK-LABEL: @exact_udiv
+#[no_mangle]
+pub unsafe fn exact_udiv(x: u32, y: u32) -> u32 {
+    // CHECK: udiv exact
+    exact_div(x, y)
+}
diff --git a/tests/codegen-llvm/intrinsics/likely.rs b/tests/codegen-llvm/intrinsics/likely.rs
new file mode 100644
index 00000000000..c5e3c466f45
--- /dev/null
+++ b/tests/codegen-llvm/intrinsics/likely.rs
@@ -0,0 +1,35 @@
+//@ compile-flags: -Copt-level=3
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+use std::intrinsics::likely;
+
+#[inline(never)]
+#[no_mangle]
+pub fn path_a() {
+    println!("path a");
+}
+
+#[inline(never)]
+#[no_mangle]
+pub fn path_b() {
+    println!("path b");
+}
+
+#[no_mangle]
+pub fn test_likely(x: bool) {
+    if likely(x) {
+        path_a();
+    } else {
+        path_b();
+    }
+}
+
+// CHECK-LABEL: @test_likely(
+// CHECK: br i1 %x, label %bb2, label %bb3, !prof ![[NUM:[0-9]+]]
+// CHECK: bb3:
+// CHECK-NOT: cold_path
+// CHECK: path_b
+// CHECK: bb2:
+// CHECK: path_a
+// CHECK: ![[NUM]] = !{!"branch_weights", {{(!"expected", )?}}i32 2000, i32 1}
diff --git a/tests/codegen-llvm/intrinsics/likely_assert.rs b/tests/codegen-llvm/intrinsics/likely_assert.rs
new file mode 100644
index 00000000000..87ffb4ee3fb
--- /dev/null
+++ b/tests/codegen-llvm/intrinsics/likely_assert.rs
@@ -0,0 +1,17 @@
+//@ compile-flags: -Copt-level=3
+#![crate_type = "lib"]
+
+#[no_mangle]
+pub fn test_assert(x: bool) {
+    assert!(x);
+}
+
+// check that assert! emits branch weights
+
+// CHECK-LABEL: @test_assert(
+// CHECK: br i1 %x, label %bb2, label %bb1, !prof ![[NUM:[0-9]+]]
+// CHECK: bb1:
+// CHECK: panic
+// CHECK: bb2:
+// CHECK: ret void
+// CHECK: ![[NUM]] = !{!"branch_weights", {{(!"expected", )?}}i32 2000, i32 1}
diff --git a/tests/codegen-llvm/intrinsics/mask.rs b/tests/codegen-llvm/intrinsics/mask.rs
new file mode 100644
index 00000000000..5344274678c
--- /dev/null
+++ b/tests/codegen-llvm/intrinsics/mask.rs
@@ -0,0 +1,12 @@
+//@ compile-flags: -Copt-level=0
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+// CHECK-LABEL: @mask_ptr
+// CHECK-SAME: [[WORD:i[0-9]+]] %mask
+#[no_mangle]
+pub fn mask_ptr(ptr: *const u16, mask: usize) -> *const u16 {
+    // CHECK: call
+    // CHECK-SAME: @llvm.ptrmask.{{p0|p0i8}}.[[WORD]](ptr {{%ptr|%1}}, [[WORD]] %mask)
+    core::intrinsics::ptr_mask(ptr, mask)
+}
diff --git a/tests/codegen-llvm/intrinsics/nontemporal.rs b/tests/codegen-llvm/intrinsics/nontemporal.rs
new file mode 100644
index 00000000000..a151d4bd297
--- /dev/null
+++ b/tests/codegen-llvm/intrinsics/nontemporal.rs
@@ -0,0 +1,32 @@
+//@ add-core-stubs
+//@ compile-flags: -Copt-level=3
+//@revisions: with_nontemporal without_nontemporal
+//@[with_nontemporal] compile-flags: --target aarch64-unknown-linux-gnu
+//@[with_nontemporal] needs-llvm-components: aarch64
+//@[without_nontemporal] compile-flags: --target x86_64-unknown-linux-gnu
+//@[without_nontemporal] needs-llvm-components: x86
+
+// Ensure that we *do* emit the `!nontemporal` flag on architectures where it
+// is well-behaved, but do *not* emit it on architectures where it is ill-behaved.
+// For more context, see <https://github.com/rust-lang/rust/issues/114582> and
+// <https://github.com/llvm/llvm-project/issues/64521>.
+
+#![feature(no_core, lang_items, intrinsics)]
+#![no_core]
+#![crate_type = "lib"]
+
+extern crate minicore;
+use minicore::*;
+
+#[rustc_intrinsic]
+pub unsafe fn nontemporal_store<T>(ptr: *mut T, val: T);
+
+#[no_mangle]
+pub fn a(a: &mut u32, b: u32) {
+    // CHECK-LABEL: define{{.*}}void @a
+    // with_nontemporal: store i32 %b, ptr %a, align 4, !nontemporal
+    // without_nontemporal-NOT: nontemporal
+    unsafe {
+        nontemporal_store(a, b);
+    }
+}
diff --git a/tests/codegen-llvm/intrinsics/offset.rs b/tests/codegen-llvm/intrinsics/offset.rs
new file mode 100644
index 00000000000..cf0c7c7ac7d
--- /dev/null
+++ b/tests/codegen-llvm/intrinsics/offset.rs
@@ -0,0 +1,33 @@
+//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+use std::intrinsics::offset;
+
+// CHECK-LABEL: ptr @offset_zst
+// CHECK-SAME: (ptr noundef %p, [[SIZE:i[0-9]+]] noundef %d)
+#[no_mangle]
+pub unsafe fn offset_zst(p: *const (), d: usize) -> *const () {
+    // CHECK-NOT: getelementptr
+    // CHECK: ret ptr %p
+    offset(p, d)
+}
+
+// CHECK-LABEL: ptr @offset_isize
+// CHECK-SAME: (ptr noundef %p, [[SIZE]] noundef %d)
+#[no_mangle]
+pub unsafe fn offset_isize(p: *const u32, d: isize) -> *const u32 {
+    // CHECK: %[[R:.*]] = getelementptr inbounds i32, ptr %p, [[SIZE]] %d
+    // CHECK-NEXT: ret ptr %[[R]]
+    offset(p, d)
+}
+
+// CHECK-LABEL: ptr @offset_usize
+// CHECK-SAME: (ptr noundef %p, [[SIZE]] noundef %d)
+#[no_mangle]
+pub unsafe fn offset_usize(p: *const u64, d: usize) -> *const u64 {
+    // CHECK: %[[R:.*]] = getelementptr inbounds{{( nuw)?}} i64, ptr %p, [[SIZE]] %d
+    // CHECK-NEXT: ret ptr %[[R]]
+    offset(p, d)
+}
diff --git a/tests/codegen-llvm/intrinsics/offset_from.rs b/tests/codegen-llvm/intrinsics/offset_from.rs
new file mode 100644
index 00000000000..ef1a77ef184
--- /dev/null
+++ b/tests/codegen-llvm/intrinsics/offset_from.rs
@@ -0,0 +1,36 @@
+//@ compile-flags: -C opt-level=1
+//@ only-64bit (because we're using [ui]size)
+
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+//! Basic optimizations are enabled because otherwise `x86_64-gnu-nopt` had an alloca.
+//! Uses a type with non-power-of-two size to avoid normalizations to shifts.
+
+use std::intrinsics::*;
+
+type RGB = [u8; 3];
+
+// CHECK-LABEL: @offset_from_odd_size
+#[no_mangle]
+pub unsafe fn offset_from_odd_size(a: *const RGB, b: *const RGB) -> isize {
+    // CHECK: start
+    // CHECK-NEXT: ptrtoint
+    // CHECK-NEXT: ptrtoint
+    // CHECK-NEXT: sub i64
+    // CHECK-NEXT: sdiv exact i64 %{{[0-9]+}}, 3
+    // CHECK-NEXT: ret i64
+    ptr_offset_from(a, b)
+}
+
+// CHECK-LABEL: @offset_from_unsigned_odd_size
+#[no_mangle]
+pub unsafe fn offset_from_unsigned_odd_size(a: *const RGB, b: *const RGB) -> usize {
+    // CHECK: start
+    // CHECK-NEXT: ptrtoint
+    // CHECK-NEXT: ptrtoint
+    // CHECK-NEXT: sub nuw i64
+    // CHECK-NEXT: udiv exact i64 %{{[0-9]+}}, 3
+    // CHECK-NEXT: ret i64
+    ptr_offset_from_unsigned(a, b)
+}
diff --git a/tests/codegen-llvm/intrinsics/prefetch.rs b/tests/codegen-llvm/intrinsics/prefetch.rs
new file mode 100644
index 00000000000..3f9f21c85cb
--- /dev/null
+++ b/tests/codegen-llvm/intrinsics/prefetch.rs
@@ -0,0 +1,64 @@
+//@ compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+use std::intrinsics::{
+    prefetch_read_data, prefetch_read_instruction, prefetch_write_data, prefetch_write_instruction,
+};
+
+#[no_mangle]
+pub fn check_prefetch_read_data(data: &[i8]) {
+    unsafe {
+        // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 0, i32 1)
+        prefetch_read_data(data.as_ptr(), 0);
+        // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 1, i32 1)
+        prefetch_read_data(data.as_ptr(), 1);
+        // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 2, i32 1)
+        prefetch_read_data(data.as_ptr(), 2);
+        // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 3, i32 1)
+        prefetch_read_data(data.as_ptr(), 3);
+    }
+}
+
+#[no_mangle]
+pub fn check_prefetch_write_data(data: &[i8]) {
+    unsafe {
+        // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 0, i32 1)
+        prefetch_write_data(data.as_ptr(), 0);
+        // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 1, i32 1)
+        prefetch_write_data(data.as_ptr(), 1);
+        // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 2, i32 1)
+        prefetch_write_data(data.as_ptr(), 2);
+        // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 3, i32 1)
+        prefetch_write_data(data.as_ptr(), 3);
+    }
+}
+
+#[no_mangle]
+pub fn check_prefetch_read_instruction(data: &[i8]) {
+    unsafe {
+        // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 0, i32 0)
+        prefetch_read_instruction(data.as_ptr(), 0);
+        // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 1, i32 0)
+        prefetch_read_instruction(data.as_ptr(), 1);
+        // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 2, i32 0)
+        prefetch_read_instruction(data.as_ptr(), 2);
+        // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 3, i32 0)
+        prefetch_read_instruction(data.as_ptr(), 3);
+    }
+}
+
+#[no_mangle]
+pub fn check_prefetch_write_instruction(data: &[i8]) {
+    unsafe {
+        // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 0, i32 0)
+        prefetch_write_instruction(data.as_ptr(), 0);
+        // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 1, i32 0)
+        prefetch_write_instruction(data.as_ptr(), 1);
+        // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 2, i32 0)
+        prefetch_write_instruction(data.as_ptr(), 2);
+        // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 3, i32 0)
+        prefetch_write_instruction(data.as_ptr(), 3);
+    }
+}
diff --git a/tests/codegen-llvm/intrinsics/ptr_metadata.rs b/tests/codegen-llvm/intrinsics/ptr_metadata.rs
new file mode 100644
index 00000000000..044dbc20486
--- /dev/null
+++ b/tests/codegen-llvm/intrinsics/ptr_metadata.rs
@@ -0,0 +1,36 @@
+//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes -Z inline-mir
+//@ only-64bit (so I don't need to worry about usize)
+
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+use std::intrinsics::ptr_metadata;
+
+// CHECK-LABEL: @thin_metadata(
+#[no_mangle]
+pub fn thin_metadata(p: *const ()) {
+    // CHECK: start
+    // CHECK-NEXT: ret void
+    ptr_metadata(p)
+}
+
+// CHECK-LABEL: @slice_metadata(
+#[no_mangle]
+pub fn slice_metadata(p: *const [u8]) -> usize {
+    // CHECK: start
+    // CHECK-NEXT: ret i64 %p.1
+    ptr_metadata(p)
+}
+
+// CHECK-LABEL: @dyn_byte_offset(
+#[no_mangle]
+pub unsafe fn dyn_byte_offset(
+    p: *const dyn std::fmt::Debug,
+    n: usize,
+) -> *const dyn std::fmt::Debug {
+    // CHECK: %[[Q:.+]] = getelementptr inbounds{{( nuw)?}} i8, ptr %p.0, i64 %n
+    // CHECK: %[[TEMP1:.+]] = insertvalue { ptr, ptr } poison, ptr %[[Q]], 0
+    // CHECK: %[[TEMP2:.+]] = insertvalue { ptr, ptr } %[[TEMP1]], ptr %p.1, 1
+    // CHECK: ret { ptr, ptr } %[[TEMP2]]
+    p.byte_add(n)
+}
diff --git a/tests/codegen-llvm/intrinsics/rotate_left.rs b/tests/codegen-llvm/intrinsics/rotate_left.rs
new file mode 100644
index 00000000000..4f6c5cbaed6
--- /dev/null
+++ b/tests/codegen-llvm/intrinsics/rotate_left.rs
@@ -0,0 +1,31 @@
+//@ compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+use std::intrinsics::rotate_left;
+
+// CHECK-LABEL: @rotate_left_u16
+#[no_mangle]
+pub unsafe fn rotate_left_u16(x: u16, shift: u32) -> u16 {
+    // CHECK: %[[tmp:.*]] = trunc i32 %shift to i16
+    // CHECK: call i16 @llvm.fshl.i16(i16 %x, i16 %x, i16 %[[tmp]])
+    rotate_left(x, shift)
+}
+
+// CHECK-LABEL: @rotate_left_u32
+#[no_mangle]
+pub unsafe fn rotate_left_u32(x: u32, shift: u32) -> u32 {
+    // CHECK-NOT: trunc
+    // CHECK-NOT: zext
+    // CHECK: call i32 @llvm.fshl.i32(i32 %x, i32 %x, i32 %shift)
+    rotate_left(x, shift)
+}
+
+// CHECK-LABEL: @rotate_left_u64
+#[no_mangle]
+pub unsafe fn rotate_left_u64(x: u64, shift: u32) -> u64 {
+    // CHECK: %[[tmp:.*]] = zext i32 %shift to i64
+    // CHECK: call i64 @llvm.fshl.i64(i64 %x, i64 %x, i64 %[[tmp]])
+    rotate_left(x, shift)
+}
diff --git a/tests/codegen-llvm/intrinsics/rustc_intrinsic_must_be_overridden.rs b/tests/codegen-llvm/intrinsics/rustc_intrinsic_must_be_overridden.rs
new file mode 100644
index 00000000000..b41e441d309
--- /dev/null
+++ b/tests/codegen-llvm/intrinsics/rustc_intrinsic_must_be_overridden.rs
@@ -0,0 +1,14 @@
+//@ revisions: OPT0 OPT1
+//@ [OPT0] compile-flags: -Copt-level=0
+//@ [OPT1] compile-flags: -Copt-level=1
+//@ compile-flags: -Cno-prepopulate-passes
+
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+// CHECK-NOT: core::intrinsics::size_of_val
+
+#[no_mangle]
+pub unsafe fn size_of_val(ptr: *const i32) -> usize {
+    core::intrinsics::size_of_val(ptr)
+}
diff --git a/tests/codegen-llvm/intrinsics/select_unpredictable.rs b/tests/codegen-llvm/intrinsics/select_unpredictable.rs
new file mode 100644
index 00000000000..ad7120c6fb8
--- /dev/null
+++ b/tests/codegen-llvm/intrinsics/select_unpredictable.rs
@@ -0,0 +1,71 @@
+//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled
+
+#![feature(core_intrinsics)]
+#![crate_type = "lib"]
+
+/* Test the intrinsic */
+
+#[no_mangle]
+pub fn test_int(p: bool, a: u64, b: u64) -> u64 {
+    // CHECK-LABEL: define{{.*}} @test_int
+    // CHECK: select i1 %p, i64 %a, i64 %b, !unpredictable
+    core::intrinsics::select_unpredictable(p, a, b)
+}
+
+#[no_mangle]
+pub fn test_pair(p: bool, a: (u64, u64), b: (u64, u64)) -> (u64, u64) {
+    // CHECK-LABEL: define{{.*}} @test_pair
+    // CHECK: select i1 %p, {{.*}}, !unpredictable
+    core::intrinsics::select_unpredictable(p, a, b)
+}
+
+struct Large {
+    e: [u64; 100],
+}
+
+#[no_mangle]
+pub fn test_struct(p: bool, a: Large, b: Large) -> Large {
+    // CHECK-LABEL: define{{.*}} @test_struct
+    // CHECK: select i1 %p, {{.*}}, !unpredictable
+    core::intrinsics::select_unpredictable(p, a, b)
+}
+
+// ZSTs should not need a `select` expression.
+#[no_mangle]
+pub fn test_zst(p: bool, a: (), b: ()) -> () {
+    // CHECK-LABEL: define{{.*}} @test_zst
+    // CHECK-NEXT: start:
+    // CHECK-NEXT: ret void
+    core::intrinsics::select_unpredictable(p, a, b)
+}
+
+/* Test the user-facing version */
+
+#[no_mangle]
+pub fn test_int2(p: bool, a: u64, b: u64) -> u64 {
+    // CHECK-LABEL: define{{.*}} @test_int2
+    // CHECK: select i1 %p, i64 %a, i64 %b, !unpredictable
+    core::hint::select_unpredictable(p, a, b)
+}
+
+#[no_mangle]
+pub fn test_pair2(p: bool, a: (u64, u64), b: (u64, u64)) -> (u64, u64) {
+    // CHECK-LABEL: define{{.*}} @test_pair2
+    // CHECK: select i1 %p, {{.*}}, !unpredictable
+    core::hint::select_unpredictable(p, a, b)
+}
+
+#[no_mangle]
+pub fn test_struct2(p: bool, a: Large, b: Large) -> Large {
+    // CHECK-LABEL: define{{.*}} @test_struct2
+    // CHECK: select i1 %p, {{.*}}, !unpredictable
+    core::hint::select_unpredictable(p, a, b)
+}
+
+#[no_mangle]
+pub fn test_zst2(p: bool, a: (), b: ()) -> () {
+    // CHECK-LABEL: define{{.*}} @test_zst2
+    // CHECK-NEXT: start:
+    // CHECK-NEXT: ret void
+    core::hint::select_unpredictable(p, a, b)
+}
diff --git a/tests/codegen-llvm/intrinsics/three_way_compare.rs b/tests/codegen-llvm/intrinsics/three_way_compare.rs
new file mode 100644
index 00000000000..95fcb636f7c
--- /dev/null
+++ b/tests/codegen-llvm/intrinsics/three_way_compare.rs
@@ -0,0 +1,28 @@
+//@ revisions: DEBUG OPTIM
+//@ [DEBUG] compile-flags: -C opt-level=0
+//@ [OPTIM] compile-flags: -C opt-level=3
+//@ compile-flags: -C no-prepopulate-passes
+//@ min-llvm-version: 20
+
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+use std::intrinsics::three_way_compare;
+
+#[no_mangle]
+// CHECK-LABEL: @signed_cmp
+// CHECK-SAME: (i16{{.*}} %a, i16{{.*}} %b)
+pub fn signed_cmp(a: i16, b: i16) -> std::cmp::Ordering {
+    // CHECK: %[[CMP:.+]] = call i8 @llvm.scmp.i8.i16(i16 %a, i16 %b)
+    // CHECK-NEXT: ret i8 %[[CMP]]
+    three_way_compare(a, b)
+}
+
+#[no_mangle]
+// CHECK-LABEL: @unsigned_cmp
+// CHECK-SAME: (i16{{.*}} %a, i16{{.*}} %b)
+pub fn unsigned_cmp(a: u16, b: u16) -> std::cmp::Ordering {
+    // CHECK: %[[CMP:.+]] = call i8 @llvm.ucmp.i8.i16(i16 %a, i16 %b)
+    // CHECK-NEXT: ret i8 %[[CMP]]
+    three_way_compare(a, b)
+}
diff --git a/tests/codegen-llvm/intrinsics/transmute-niched.rs b/tests/codegen-llvm/intrinsics/transmute-niched.rs
new file mode 100644
index 00000000000..8ff5cc8ee4f
--- /dev/null
+++ b/tests/codegen-llvm/intrinsics/transmute-niched.rs
@@ -0,0 +1,223 @@
+//@ revisions: OPT DBG
+//@ [OPT] compile-flags: -C opt-level=3 -C no-prepopulate-passes
+//@ [DBG] compile-flags: -C opt-level=0 -C no-prepopulate-passes
+//@ only-64bit (so I don't need to worry about usize)
+#![crate_type = "lib"]
+
+use std::mem::transmute;
+use std::num::NonZero;
+use std::ptr::NonNull;
+
+#[repr(u8)]
+pub enum SmallEnum {
+    A = 10,
+    B = 11,
+    C = 12,
+}
+
+// CHECK-LABEL: @check_to_enum(
+#[no_mangle]
+pub unsafe fn check_to_enum(x: i8) -> SmallEnum {
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
+    // OPT: %0 = sub i8 %x, 10
+    // OPT: %1 = icmp ule i8 %0, 2
+    // OPT: call void @llvm.assume(i1 %1)
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
+    // CHECK: ret i8 %x
+
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_from_enum(
+#[no_mangle]
+pub unsafe fn check_from_enum(x: SmallEnum) -> i8 {
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
+    // OPT: %0 = sub i8 %x, 10
+    // OPT: %1 = icmp ule i8 %0, 2
+    // OPT: call void @llvm.assume(i1 %1)
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
+    // CHECK: ret i8 %x
+
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_to_ordering(
+#[no_mangle]
+pub unsafe fn check_to_ordering(x: u8) -> std::cmp::Ordering {
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
+    // OPT: %0 = sub i8 %x, -1
+    // OPT: %1 = icmp ule i8 %0, 2
+    // OPT: call void @llvm.assume(i1 %1)
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
+    // CHECK: ret i8 %x
+
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_from_ordering(
+#[no_mangle]
+pub unsafe fn check_from_ordering(x: std::cmp::Ordering) -> u8 {
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
+    // OPT: %0 = sub i8 %x, -1
+    // OPT: %1 = icmp ule i8 %0, 2
+    // OPT: call void @llvm.assume(i1 %1)
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
+    // CHECK: ret i8 %x
+
+    transmute(x)
+}
+
+#[repr(i32)]
+pub enum Minus100ToPlus100 {
+    A = -100,
+    B = -90,
+    C = -80,
+    D = -70,
+    E = -60,
+    F = -50,
+    G = -40,
+    H = -30,
+    I = -20,
+    J = -10,
+    K = 0,
+    L = 10,
+    M = 20,
+    N = 30,
+    O = 40,
+    P = 50,
+    Q = 60,
+    R = 70,
+    S = 80,
+    T = 90,
+    U = 100,
+}
+
+// CHECK-LABEL: @check_enum_from_char(
+#[no_mangle]
+pub unsafe fn check_enum_from_char(x: char) -> Minus100ToPlus100 {
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
+    // OPT: %0 = icmp ule i32 %x, 1114111
+    // OPT: call void @llvm.assume(i1 %0)
+    // OPT: %1 = sub i32 %x, -100
+    // OPT: %2 = icmp ule i32 %1, 200
+    // OPT: call void @llvm.assume(i1 %2)
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
+    // CHECK: ret i32 %x
+
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_enum_to_char(
+#[no_mangle]
+pub unsafe fn check_enum_to_char(x: Minus100ToPlus100) -> char {
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
+    // OPT: %0 = sub i32 %x, -100
+    // OPT: %1 = icmp ule i32 %0, 200
+    // OPT: call void @llvm.assume(i1 %1)
+    // OPT: %2 = icmp ule i32 %x, 1114111
+    // OPT: call void @llvm.assume(i1 %2)
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
+    // CHECK: ret i32 %x
+
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_swap_pair(
+#[no_mangle]
+pub unsafe fn check_swap_pair(x: (char, NonZero<u32>)) -> (NonZero<u32>, char) {
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
+    // OPT: %0 = icmp ule i32 %x.0, 1114111
+    // OPT: call void @llvm.assume(i1 %0)
+    // OPT: %1 = sub i32 %x.0, 1
+    // OPT: %2 = icmp ule i32 %1, -2
+    // OPT: call void @llvm.assume(i1 %2)
+    // OPT: %3 = sub i32 %x.1, 1
+    // OPT: %4 = icmp ule i32 %3, -2
+    // OPT: call void @llvm.assume(i1 %4)
+    // OPT: %5 = icmp ule i32 %x.1, 1114111
+    // OPT: call void @llvm.assume(i1 %5)
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
+    // CHECK: %[[P1:.+]] = insertvalue { i32, i32 } poison, i32 %x.0, 0
+    // CHECK: %[[P2:.+]] = insertvalue { i32, i32 } %[[P1]], i32 %x.1, 1
+    // CHECK: ret { i32, i32 } %[[P2]]
+
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_bool_from_ordering(
+#[no_mangle]
+pub unsafe fn check_bool_from_ordering(x: std::cmp::Ordering) -> bool {
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
+    // OPT: %0 = sub i8 %x, -1
+    // OPT: %1 = icmp ule i8 %0, 2
+    // OPT: call void @llvm.assume(i1 %1)
+    // OPT: %2 = icmp ule i8 %x, 1
+    // OPT: call void @llvm.assume(i1 %2)
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
+    // CHECK: %[[R:.+]] = trunc{{( nuw)?}} i8 %x to i1
+    // CHECK: ret i1 %[[R]]
+
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_bool_to_ordering(
+#[no_mangle]
+pub unsafe fn check_bool_to_ordering(x: bool) -> std::cmp::Ordering {
+    // CHECK: %_0 = zext i1 %x to i8
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
+    // OPT: %0 = icmp ule i8 %_0, 1
+    // OPT: call void @llvm.assume(i1 %0)
+    // OPT: %1 = sub i8 %_0, -1
+    // OPT: %2 = icmp ule i8 %1, 2
+    // OPT: call void @llvm.assume(i1 %2)
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
+    // CHECK: ret i8 %_0
+
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_nonnull_to_ptr(
+#[no_mangle]
+pub unsafe fn check_nonnull_to_ptr(x: NonNull<u8>) -> *const u8 {
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
+    // OPT: %0 = icmp ne ptr %x, null
+    // OPT: call void @llvm.assume(i1 %0)
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
+    // CHECK: ret ptr %x
+
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_ptr_to_nonnull(
+#[no_mangle]
+pub unsafe fn check_ptr_to_nonnull(x: *const u8) -> NonNull<u8> {
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
+    // OPT: %0 = icmp ne ptr %x, null
+    // OPT: call void @llvm.assume(i1 %0)
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
+    // CHECK: ret ptr %x
+
+    transmute(x)
+}
diff --git a/tests/codegen-llvm/intrinsics/transmute-x64.rs b/tests/codegen-llvm/intrinsics/transmute-x64.rs
new file mode 100644
index 00000000000..8c9480ab091
--- /dev/null
+++ b/tests/codegen-llvm/intrinsics/transmute-x64.rs
@@ -0,0 +1,28 @@
+//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes
+//@ only-x86_64 (it's using arch-specific types)
+
+#![crate_type = "lib"]
+
+use std::arch::x86_64::{__m128, __m128i, __m256i};
+use std::mem::transmute;
+
+// CHECK-LABEL: @check_sse_pair_to_avx(
+#[no_mangle]
+pub unsafe fn check_sse_pair_to_avx(x: (__m128i, __m128i)) -> __m256i {
+    // CHECK: start:
+    // CHECK-NOT: alloca
+    // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 32 %_0, ptr align 16 %x, i64 32, i1 false)
+    // CHECK-NEXT: ret void
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_sse_pair_from_avx(
+#[no_mangle]
+pub unsafe fn check_sse_pair_from_avx(x: __m256i) -> (__m128i, __m128i) {
+    // CHECK: start:
+    // CHECK-NOT: alloca
+    // CHECK-NEXT: %[[TEMP:.+]] = load <4 x i64>, ptr %x, align 32
+    // CHECK-NEXT: store <4 x i64> %[[TEMP]], ptr %_0, align 16
+    // CHECK-NEXT: ret void
+    transmute(x)
+}
diff --git a/tests/codegen-llvm/intrinsics/transmute.rs b/tests/codegen-llvm/intrinsics/transmute.rs
new file mode 100644
index 00000000000..c9a1cd58af3
--- /dev/null
+++ b/tests/codegen-llvm/intrinsics/transmute.rs
@@ -0,0 +1,497 @@
+//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes
+//@ only-64bit (so I don't need to worry about usize)
+
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+#![feature(custom_mir)]
+#![allow(unreachable_code)]
+
+// Some of these need custom MIR to not get removed by MIR optimizations.
+use std::intrinsics::mir::*;
+use std::intrinsics::{transmute, transmute_unchecked};
+use std::mem::MaybeUninit;
+use std::num::NonZero;
+
+pub enum ZstNever {}
+
+#[repr(align(2))]
+pub struct BigNever(ZstNever, u16, ZstNever);
+
+#[repr(align(8))]
+pub struct Scalar64(i64);
+
+#[repr(C, align(4))]
+pub struct Aggregate64(u16, u8, i8, f32);
+
+#[repr(C)]
+pub struct Aggregate8(u8);
+
+// CHECK-LABEL: @check_bigger_size(
+#[no_mangle]
+pub unsafe fn check_bigger_size(x: u16) -> u32 {
+    // CHECK: store i1 true, ptr poison, align 1
+    transmute_unchecked(x)
+}
+
+// CHECK-LABEL: @check_smaller_size(
+#[no_mangle]
+pub unsafe fn check_smaller_size(x: u32) -> u16 {
+    // CHECK: store i1 true, ptr poison, align 1
+    transmute_unchecked(x)
+}
+
+// CHECK-LABEL: @check_smaller_array(
+#[no_mangle]
+pub unsafe fn check_smaller_array(x: [u32; 7]) -> [u32; 3] {
+    // CHECK: store i1 true, ptr poison, align 1
+    transmute_unchecked(x)
+}
+
+// CHECK-LABEL: @check_bigger_array(
+#[no_mangle]
+pub unsafe fn check_bigger_array(x: [u32; 3]) -> [u32; 7] {
+    // CHECK: store i1 true, ptr poison, align 1
+    transmute_unchecked(x)
+}
+
+// CHECK-LABEL: @check_to_empty_array(
+#[no_mangle]
+#[custom_mir(dialect = "runtime", phase = "optimized")]
+pub unsafe fn check_to_empty_array(x: [u32; 5]) -> [u32; 0] {
+    // CHECK: start
+    // CHECK-NEXT: store i1 true, ptr poison, align 1
+    // CHECK-NEXT: ret void
+    mir! {
+        {
+            RET = CastTransmute(x);
+            Return()
+        }
+    }
+}
+
+// CHECK-LABEL: @check_from_empty_array(
+#[no_mangle]
+#[custom_mir(dialect = "runtime", phase = "optimized")]
+pub unsafe fn check_from_empty_array(x: [u32; 0]) -> [u32; 5] {
+    // CHECK: start
+    // CHECK-NEXT: store i1 true, ptr poison, align 1
+    // CHECK-NEXT: ret void
+    mir! {
+        {
+            RET = CastTransmute(x);
+            Return()
+        }
+    }
+}
+
+// CHECK-LABEL: @check_to_uninhabited(
+#[no_mangle]
+#[custom_mir(dialect = "runtime", phase = "optimized")]
+pub unsafe fn check_to_uninhabited(x: u16) {
+    // CHECK: start
+    // CHECK-NEXT: store i1 true, ptr poison, align 1
+    // CHECK-NEXT: ret void
+    mir! {
+        let temp: BigNever;
+        {
+            temp = CastTransmute(x);
+            Return()
+        }
+    }
+}
+
+// CHECK-LABEL: @check_from_uninhabited(
+#[no_mangle]
+#[custom_mir(dialect = "runtime", phase = "optimized")]
+pub unsafe fn check_from_uninhabited(x: BigNever) -> u16 {
+    // CHECK: start
+    // CHECK-NEXT: store i1 true, ptr poison, align 1
+    // CHECK-NEXT: ret i16 poison
+    mir! {
+        {
+            RET = CastTransmute(x);
+            Return()
+        }
+    }
+}
+
+// CHECK-LABEL: @check_intermediate_passthrough(
+#[no_mangle]
+pub unsafe fn check_intermediate_passthrough(x: u32) -> i32 {
+    // CHECK: start
+    // CHECK: %[[TMP:.+]] = add i32 1, %x
+    // CHECK: %[[RET:.+]] = add i32 %[[TMP]], 1
+    // CHECK: ret i32 %[[RET]]
+    unsafe { transmute::<u32, i32>(1 + x) + 1 }
+}
+
+// CHECK-LABEL: @check_nop_pair(
+#[no_mangle]
+pub unsafe fn check_nop_pair(x: (u8, i8)) -> (i8, u8) {
+    // CHECK-NOT: alloca
+    // CHECK: %0 = insertvalue { i8, i8 } poison, i8 %x.0, 0
+    // CHECK: %1 = insertvalue { i8, i8 } %0, i8 %x.1, 1
+    // CHECK: ret { i8, i8 } %1
+    unsafe { transmute(x) }
+}
+
+// CHECK-LABEL: @check_to_newtype(
+#[no_mangle]
+pub unsafe fn check_to_newtype(x: u64) -> Scalar64 {
+    // CHECK-NOT: alloca
+    // CHECK: ret i64 %x
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_from_newtype(
+#[no_mangle]
+pub unsafe fn check_from_newtype(x: Scalar64) -> u64 {
+    // CHECK-NOT: alloca
+    // CHECK: ret i64 %x
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_aggregate_to_bool(
+#[no_mangle]
+pub unsafe fn check_aggregate_to_bool(x: Aggregate8) -> bool {
+    // CHECK: %x = alloca [1 x i8], align 1
+    // CHECK: %[[BYTE:.+]] = load i8, ptr %x, align 1
+    // CHECK: %[[BOOL:.+]] = trunc nuw i8 %[[BYTE]] to i1
+    // CHECK: ret i1 %[[BOOL]]
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_aggregate_from_bool(
+#[no_mangle]
+pub unsafe fn check_aggregate_from_bool(x: bool) -> Aggregate8 {
+    // CHECK: %_0 = alloca [1 x i8], align 1
+    // CHECK: %[[BYTE:.+]] = zext i1 %x to i8
+    // CHECK: store i8 %[[BYTE]], ptr %_0, align 1
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_byte_to_bool(
+#[no_mangle]
+pub unsafe fn check_byte_to_bool(x: u8) -> bool {
+    // CHECK-NOT: alloca
+    // CHECK: %[[R:.+]] = trunc nuw i8 %x to i1
+    // CHECK: ret i1 %[[R]]
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_byte_from_bool(
+#[no_mangle]
+pub unsafe fn check_byte_from_bool(x: bool) -> u8 {
+    // CHECK-NOT: alloca
+    // CHECK: %[[R:.+]] = zext i1 %x to i8
+    // CHECK: ret i8 %[[R:.+]]
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_to_pair(
+#[no_mangle]
+pub unsafe fn check_to_pair(x: u64) -> Option<i32> {
+    // CHECK: %_0 = alloca [8 x i8], align 4
+    // CHECK: store i64 %x, ptr %_0, align 4
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_from_pair(
+#[no_mangle]
+pub unsafe fn check_from_pair(x: Option<i32>) -> u64 {
+    // The two arguments are of types that are only 4-aligned, but they're
+    // immediates so we can write using the destination alloca's alignment.
+    const { assert!(std::mem::align_of::<Option<i32>>() == 4) };
+
+    // CHECK: %_0 = alloca [8 x i8], align 8
+    // CHECK: store i32 %x.0, ptr %_0, align 8
+    // CHECK: store i32 %x.1, ptr %0, align 4
+    // CHECK: %[[R:.+]] = load i64, ptr %_0, align 8
+    // CHECK: ret i64 %[[R]]
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_to_float(
+#[no_mangle]
+pub unsafe fn check_to_float(x: u32) -> f32 {
+    // CHECK-NOT: alloca
+    // CHECK: %_0 = bitcast i32 %x to float
+    // CHECK: ret float %_0
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_from_float(
+#[no_mangle]
+pub unsafe fn check_from_float(x: f32) -> u32 {
+    // CHECK-NOT: alloca
+    // CHECK: %_0 = bitcast float %x to i32
+    // CHECK: ret i32 %_0
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_to_bytes(
+#[no_mangle]
+pub unsafe fn check_to_bytes(x: u32) -> [u8; 4] {
+    // CHECK: %_0 = alloca [4 x i8], align 1
+    // CHECK: store i32 %x, ptr %_0, align 1
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_from_bytes(
+#[no_mangle]
+pub unsafe fn check_from_bytes(x: [u8; 4]) -> u32 {
+    // CHECK: %x = alloca [4 x i8], align 1
+    // CHECK: %[[VAL:.+]] = load i32, ptr %x, align 1
+    // CHECK: ret i32 %[[VAL]]
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_to_aggregate(
+#[no_mangle]
+pub unsafe fn check_to_aggregate(x: u64) -> Aggregate64 {
+    // CHECK: %_0 = alloca [8 x i8], align 4
+    // CHECK: store i64 %x, ptr %_0, align 4
+    // CHECK: %0 = load i64, ptr %_0, align 4
+    // CHECK: ret i64 %0
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_from_aggregate(
+#[no_mangle]
+pub unsafe fn check_from_aggregate(x: Aggregate64) -> u64 {
+    // CHECK: %x = alloca [8 x i8], align 4
+    // CHECK: %[[VAL:.+]] = load i64, ptr %x, align 4
+    // CHECK: ret i64 %[[VAL]]
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_long_array_less_aligned(
+#[no_mangle]
+pub unsafe fn check_long_array_less_aligned(x: [u64; 100]) -> [u16; 400] {
+    // CHECK-NEXT: start
+    // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 2 %_0, ptr align 8 %x, i64 800, i1 false)
+    // CHECK-NEXT: ret void
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_long_array_more_aligned(
+#[no_mangle]
+pub unsafe fn check_long_array_more_aligned(x: [u8; 100]) -> [u32; 25] {
+    // CHECK-NEXT: start
+    // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %_0, ptr align 1 %x, i64 100, i1 false)
+    // CHECK-NEXT: ret void
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_pair_with_bool(
+#[no_mangle]
+pub unsafe fn check_pair_with_bool(x: (u8, bool)) -> (bool, i8) {
+    // CHECK-NOT: alloca
+    // CHECK: trunc nuw i8 %x.0 to i1
+    // CHECK: zext i1 %x.1 to i8
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_float_to_pointer(
+#[no_mangle]
+pub unsafe fn check_float_to_pointer(x: f64) -> *const () {
+    // CHECK-NOT: alloca
+    // CHECK: %0 = bitcast double %x to i64
+    // CHECK: %_0 = getelementptr i8, ptr null, i64 %0
+    // CHECK: ret ptr %_0
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_float_from_pointer(
+#[no_mangle]
+pub unsafe fn check_float_from_pointer(x: *const ()) -> f64 {
+    // CHECK-NOT: alloca
+    // CHECK: %0 = ptrtoint ptr %x to i64
+    // CHECK: %_0 = bitcast i64 %0 to double
+    // CHECK: ret double %_0
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_array_to_pair(
+#[no_mangle]
+pub unsafe fn check_array_to_pair(x: [u8; 16]) -> (i64, u64) {
+    // CHECK-NOT: alloca
+    // CHECK: %[[FST:.+]] = load i64, ptr %{{.+}}, align 1, !noundef !
+    // CHECK: %[[SND:.+]] = load i64, ptr %{{.+}}, align 1, !noundef !
+    // CHECK: %[[PAIR0:.+]] = insertvalue { i64, i64 } poison, i64 %[[FST]], 0
+    // CHECK: %[[PAIR01:.+]] = insertvalue { i64, i64 } %[[PAIR0]], i64 %[[SND]], 1
+    // CHECK: ret { i64, i64 } %[[PAIR01]]
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_pair_to_array(
+#[no_mangle]
+pub unsafe fn check_pair_to_array(x: (i64, u64)) -> [u8; 16] {
+    // CHECK-NOT: alloca
+    // CHECK: store i64 %x.0, ptr %{{.+}}, align 1
+    // CHECK: store i64 %x.1, ptr %{{.+}}, align 1
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_heterogeneous_integer_pair(
+#[no_mangle]
+pub unsafe fn check_heterogeneous_integer_pair(x: (i32, bool)) -> (bool, u32) {
+    // CHECK: store i32 %x.0
+    // CHECK: %[[WIDER:.+]] = zext i1 %x.1 to i8
+    // CHECK: store i8 %[[WIDER]]
+
+    // CHECK: %[[BYTE:.+]] = load i8
+    // CHECK: trunc nuw i8 %[[BYTE:.+]] to i1
+    // CHECK: load i32
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_heterogeneous_float_pair(
+#[no_mangle]
+pub unsafe fn check_heterogeneous_float_pair(x: (f64, f32)) -> (f32, f64) {
+    // CHECK: store double %x.0
+    // CHECK: store float %x.1
+    // CHECK: %[[A:.+]] = load float
+    // CHECK: %[[B:.+]] = load double
+    // CHECK: %[[P:.+]] = insertvalue { float, double } poison, float %[[A]], 0
+    // CHECK: insertvalue { float, double } %[[P]], double %[[B]], 1
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_issue_110005(
+#[no_mangle]
+pub unsafe fn check_issue_110005(x: (usize, bool)) -> Option<Box<[u8]>> {
+    // CHECK: store i64 %x.0
+    // CHECK: %[[WIDER:.+]] = zext i1 %x.1 to i8
+    // CHECK: store i8 %[[WIDER]]
+    // CHECK: load ptr
+    // CHECK: load i64
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_pair_to_dst_ref(
+#[no_mangle]
+pub unsafe fn check_pair_to_dst_ref<'a>(x: (usize, usize)) -> &'a [u8] {
+    // CHECK: %_0.0 = getelementptr i8, ptr null, i64 %x.0
+    // CHECK: %0 = icmp ne ptr %_0.0, null
+    // CHECK: call void @llvm.assume(i1 %0)
+    // CHECK: %1 = insertvalue { ptr, i64 } poison, ptr %_0.0, 0
+    // CHECK: %2 = insertvalue { ptr, i64 } %1, i64 %x.1, 1
+    // CHECK: ret { ptr, i64 } %2
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_issue_109992(
+#[no_mangle]
+#[custom_mir(dialect = "runtime", phase = "optimized")]
+pub unsafe fn check_issue_109992(x: ()) -> [(); 1] {
+    // This uses custom MIR to avoid MIR optimizations having removed ZST ops.
+
+    // CHECK: start
+    // CHECK-NEXT: ret void
+    mir! {
+        {
+            RET = CastTransmute(x);
+            Return()
+        }
+    }
+}
+
+// CHECK-LABEL: @check_unit_to_never(
+#[no_mangle]
+#[custom_mir(dialect = "runtime", phase = "optimized")]
+pub unsafe fn check_unit_to_never(x: ()) {
+    // This uses custom MIR to avoid MIR optimizations having removed ZST ops.
+
+    // CHECK: start
+    // CHECK-NEXT: store i1 true, ptr poison, align 1
+    // CHECK-NEXT: ret void
+    mir! {
+        let temp: ZstNever;
+        {
+            temp = CastTransmute(x);
+            Return()
+        }
+    }
+}
+
+// CHECK-LABEL: @check_unit_from_never(
+#[no_mangle]
+#[custom_mir(dialect = "runtime", phase = "optimized")]
+pub unsafe fn check_unit_from_never(x: ZstNever) -> () {
+    // This uses custom MIR to avoid MIR optimizations having removed ZST ops.
+
+    // CHECK: start
+    // CHECK-NEXT: store i1 true, ptr poison, align 1
+    // CHECK-NEXT: ret void
+    mir! {
+        {
+            RET = CastTransmute(x);
+            Return()
+        }
+    }
+}
+
+// CHECK-LABEL: @check_maybe_uninit_pair(i16 %x.0, i64 %x.1)
+#[no_mangle]
+pub unsafe fn check_maybe_uninit_pair(
+    x: (MaybeUninit<u16>, MaybeUninit<u64>),
+) -> (MaybeUninit<i64>, MaybeUninit<i16>) {
+    // Thanks to `MaybeUninit` this is actually defined behaviour,
+    // unlike the examples above with pairs of primitives.
+
+    // CHECK: store i16 %x.0
+    // CHECK: store i64 %x.1
+    // CHECK: load i64
+    // CHECK-NOT: noundef
+    // CHECK: load i16
+    // CHECK-NOT: noundef
+    // CHECK: ret { i64, i16 }
+    transmute(x)
+}
+
+#[repr(align(8))]
+pub struct HighAlignScalar(u8);
+
+// CHECK-LABEL: @check_to_overalign(
+#[no_mangle]
+pub unsafe fn check_to_overalign(x: u64) -> HighAlignScalar {
+    // CHECK: %_0 = alloca [8 x i8], align 8
+    // CHECK: store i64 %x, ptr %_0, align 8
+    // CHECK: %0 = load i64, ptr %_0, align 8
+    // CHECK: ret i64 %0
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_from_overalign(
+#[no_mangle]
+pub unsafe fn check_from_overalign(x: HighAlignScalar) -> u64 {
+    // CHECK: %x = alloca [8 x i8], align 8
+    // CHECK: %[[VAL:.+]] = load i64, ptr %x, align 8
+    // CHECK: ret i64 %[[VAL]]
+    transmute(x)
+}
+
+#[repr(transparent)]
+struct Level1(std::num::NonZero<u32>);
+#[repr(transparent)]
+struct Level2(Level1);
+#[repr(transparent)]
+struct Level3(Level2);
+
+// CHECK-LABEL: @repeatedly_transparent_transmute
+// CHECK-SAME: (i32{{.+}}%[[ARG:[^)]+]])
+#[no_mangle]
+#[custom_mir(dialect = "runtime", phase = "optimized")]
+pub unsafe fn repeatedly_transparent_transmute(x: NonZero<u32>) -> Level3 {
+    // CHECK: start
+    // CHECK-NEXT: ret i32 %[[ARG]]
+    mir! {
+        {
+            let A = CastTransmute::<NonZero<u32>, Level1>(x);
+            let B = CastTransmute::<Level1, Level2>(A);
+            RET = CastTransmute::<Level2, Level3>(B);
+            Return()
+        }
+    }
+}
diff --git a/tests/codegen-llvm/intrinsics/typed_swap.rs b/tests/codegen-llvm/intrinsics/typed_swap.rs
new file mode 100644
index 00000000000..6b55078407a
--- /dev/null
+++ b/tests/codegen-llvm/intrinsics/typed_swap.rs
@@ -0,0 +1,77 @@
+//@ revisions: OPT0 OPT3
+//@ [OPT0] compile-flags: -Copt-level=0
+//@ [OPT3] compile-flags: -Copt-level=3
+//@ compile-flags: -C no-prepopulate-passes
+//@ only-64bit (so I don't need to worry about usize)
+// ignore-tidy-linelength (the memcpy calls get long)
+
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+use std::intrinsics::typed_swap_nonoverlapping;
+
+// CHECK-LABEL: @swap_unit(
+#[no_mangle]
+pub unsafe fn swap_unit(x: &mut (), y: &mut ()) {
+    // CHECK: start
+    // CHECK-NEXT: ret void
+    typed_swap_nonoverlapping(x, y)
+}
+
+// CHECK-LABEL: @swap_i32(
+#[no_mangle]
+pub unsafe fn swap_i32(x: &mut i32, y: &mut i32) {
+    // CHECK-NOT: alloca
+
+    // CHECK: %[[TEMP:.+]] = load i32, ptr %x, align 4
+    // OPT3-SAME: !noundef
+    // OPT0: %[[TEMP2:.+]] = load i32, ptr %y, align 4
+    // OPT0: store i32 %[[TEMP2]], ptr %x, align 4
+    // OPT0-NOT: memcpy
+    // OPT3-NOT: load
+    // OPT3: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %x, ptr align 4 %y, i64 4, i1 false)
+    // CHECK: store i32 %[[TEMP]], ptr %y, align 4
+    // CHECK: ret void
+    typed_swap_nonoverlapping(x, y)
+}
+
+// CHECK-LABEL: @swap_pair(
+#[no_mangle]
+pub unsafe fn swap_pair(x: &mut (i32, u32), y: &mut (i32, u32)) {
+    // CHECK-NOT: alloca
+
+    // CHECK: load i32
+    // OPT3-SAME: !noundef
+    // CHECK: load i32
+    // OPT3-SAME: !noundef
+    // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %x, ptr align 4 %y, i64 8, i1 false)
+    // CHECK: store i32
+    // CHECK: store i32
+    typed_swap_nonoverlapping(x, y)
+}
+
+// CHECK-LABEL: @swap_str(
+#[no_mangle]
+pub unsafe fn swap_str<'a>(x: &mut &'a str, y: &mut &'a str) {
+    // CHECK-NOT: alloca
+
+    // CHECK: load ptr
+    // OPT3-SAME: !nonnull
+    // OPT3-SAME: !noundef
+    // CHECK: load i64
+    // OPT3-SAME: !noundef
+    // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %x, ptr align 8 %y, i64 16, i1 false)
+    // CHECK: store ptr
+    // CHECK: store i64
+    typed_swap_nonoverlapping(x, y)
+}
+
+// OPT0-LABEL: @swap_string(
+#[no_mangle]
+pub unsafe fn swap_string(x: &mut String, y: &mut String) {
+    // OPT0: %[[TEMP:.+]] = alloca {{.+}}, align 8
+    // OPT0: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %[[TEMP]], ptr align 8 %x, i64 24, i1 false)
+    // OPT0: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %x, ptr align 8 %y, i64 24, i1 false)
+    // OPT0: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %y, ptr align 8 %[[TEMP]], i64 24, i1 false)
+    typed_swap_nonoverlapping(x, y)
+}
diff --git a/tests/codegen-llvm/intrinsics/unchecked_math.rs b/tests/codegen-llvm/intrinsics/unchecked_math.rs
new file mode 100644
index 00000000000..419c120ede9
--- /dev/null
+++ b/tests/codegen-llvm/intrinsics/unchecked_math.rs
@@ -0,0 +1,46 @@
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+use std::intrinsics::*;
+
+// CHECK-LABEL: @unchecked_add_signed
+#[no_mangle]
+pub unsafe fn unchecked_add_signed(a: i32, b: i32) -> i32 {
+    // CHECK: add nsw
+    unchecked_add(a, b)
+}
+
+// CHECK-LABEL: @unchecked_add_unsigned
+#[no_mangle]
+pub unsafe fn unchecked_add_unsigned(a: u32, b: u32) -> u32 {
+    // CHECK: add nuw
+    unchecked_add(a, b)
+}
+
+// CHECK-LABEL: @unchecked_sub_signed
+#[no_mangle]
+pub unsafe fn unchecked_sub_signed(a: i32, b: i32) -> i32 {
+    // CHECK: sub nsw
+    unchecked_sub(a, b)
+}
+
+// CHECK-LABEL: @unchecked_sub_unsigned
+#[no_mangle]
+pub unsafe fn unchecked_sub_unsigned(a: u32, b: u32) -> u32 {
+    // CHECK: sub nuw
+    unchecked_sub(a, b)
+}
+
+// CHECK-LABEL: @unchecked_mul_signed
+#[no_mangle]
+pub unsafe fn unchecked_mul_signed(a: i32, b: i32) -> i32 {
+    // CHECK: mul nsw
+    unchecked_mul(a, b)
+}
+
+// CHECK-LABEL: @unchecked_mul_unsigned
+#[no_mangle]
+pub unsafe fn unchecked_mul_unsigned(a: u32, b: u32) -> u32 {
+    // CHECK: mul nuw
+    unchecked_mul(a, b)
+}
diff --git a/tests/codegen-llvm/intrinsics/unlikely.rs b/tests/codegen-llvm/intrinsics/unlikely.rs
new file mode 100644
index 00000000000..90ebf070d27
--- /dev/null
+++ b/tests/codegen-llvm/intrinsics/unlikely.rs
@@ -0,0 +1,35 @@
+//@ compile-flags: -Copt-level=3
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+use std::intrinsics::unlikely;
+
+#[inline(never)]
+#[no_mangle]
+pub fn path_a() {
+    println!("path a");
+}
+
+#[inline(never)]
+#[no_mangle]
+pub fn path_b() {
+    println!("path b");
+}
+
+#[no_mangle]
+pub fn test_unlikely(x: bool) {
+    if unlikely(x) {
+        path_a();
+    } else {
+        path_b();
+    }
+}
+
+// CHECK-LABEL: @test_unlikely(
+// CHECK: br i1 %x, label %bb2, label %bb4, !prof ![[NUM:[0-9]+]]
+// CHECK: bb4:
+// CHECK: path_b
+// CHECK: bb2:
+// CHECK-NOT: cold_path
+// CHECK: path_a
+// CHECK: ![[NUM]] = !{!"branch_weights", {{(!"expected", )?}}i32 1, i32 2000}
diff --git a/tests/codegen-llvm/intrinsics/volatile.rs b/tests/codegen-llvm/intrinsics/volatile.rs
new file mode 100644
index 00000000000..2dea5ecb2ca
--- /dev/null
+++ b/tests/codegen-llvm/intrinsics/volatile.rs
@@ -0,0 +1,55 @@
+//@ compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+use std::intrinsics;
+
+// CHECK-LABEL: @volatile_copy_memory
+#[no_mangle]
+pub unsafe fn volatile_copy_memory(a: *mut u8, b: *const u8) {
+    // CHECK: llvm.memmove.{{\w*(.*true)}}
+    intrinsics::volatile_copy_memory(a, b, 1)
+}
+
+// CHECK-LABEL: @volatile_copy_nonoverlapping_memory
+#[no_mangle]
+pub unsafe fn volatile_copy_nonoverlapping_memory(a: *mut u8, b: *const u8) {
+    // CHECK: llvm.memcpy.{{\w*(.*true)}}
+    intrinsics::volatile_copy_nonoverlapping_memory(a, b, 1)
+}
+
+// CHECK-LABEL: @volatile_set_memory
+#[no_mangle]
+pub unsafe fn volatile_set_memory(a: *mut u8, b: u8) {
+    // CHECK: llvm.memset.{{\w*(.*true)}}
+    intrinsics::volatile_set_memory(a, b, 1)
+}
+
+// CHECK-LABEL: @volatile_load
+#[no_mangle]
+pub unsafe fn volatile_load(a: *const u8) -> u8 {
+    // CHECK: load volatile
+    intrinsics::volatile_load(a)
+}
+
+// CHECK-LABEL: @volatile_store
+#[no_mangle]
+pub unsafe fn volatile_store(a: *mut u8, b: u8) {
+    // CHECK: store volatile
+    intrinsics::volatile_store(a, b)
+}
+
+// CHECK-LABEL: @unaligned_volatile_load
+#[no_mangle]
+pub unsafe fn unaligned_volatile_load(a: *const u8) -> u8 {
+    // CHECK: load volatile
+    intrinsics::unaligned_volatile_load(a)
+}
+
+// CHECK-LABEL: @unaligned_volatile_store
+#[no_mangle]
+pub unsafe fn unaligned_volatile_store(a: *mut u8, b: u8) {
+    // CHECK: store volatile
+    intrinsics::unaligned_volatile_store(a, b)
+}
diff --git a/tests/codegen-llvm/intrinsics/volatile_order.rs b/tests/codegen-llvm/intrinsics/volatile_order.rs
new file mode 100644
index 00000000000..99469831a6c
--- /dev/null
+++ b/tests/codegen-llvm/intrinsics/volatile_order.rs
@@ -0,0 +1,18 @@
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+use std::intrinsics::*;
+
+pub unsafe fn test_volatile_order() {
+    let mut a: Box<u8> = Box::new(0);
+    // CHECK: load volatile
+    let x = volatile_load(&*a);
+    // CHECK: load volatile
+    let x = volatile_load(&*a);
+    // CHECK: store volatile
+    volatile_store(&mut *a, 12);
+    // CHECK: store volatile
+    unaligned_volatile_store(&mut *a, 12);
+    // CHECK: llvm.memset.p0
+    volatile_set_memory(&mut *a, 12, 1)
+}
diff --git a/tests/codegen-llvm/is_val_statically_known.rs b/tests/codegen-llvm/is_val_statically_known.rs
new file mode 100644
index 00000000000..8119d3a3bf6
--- /dev/null
+++ b/tests/codegen-llvm/is_val_statically_known.rs
@@ -0,0 +1,163 @@
+//@ compile-flags: --crate-type=lib -Zmerge-functions=disabled -Copt-level=3
+
+#![feature(core_intrinsics)]
+#![feature(f16, f128)]
+
+use std::intrinsics::is_val_statically_known;
+
+pub struct A(u32);
+pub enum B {
+    Ye(u32),
+}
+
+#[inline]
+pub fn _u32(a: u32) -> i32 {
+    if is_val_statically_known(a) { 1 } else { 0 }
+}
+
+// CHECK-LABEL: @_u32_true(
+#[no_mangle]
+pub fn _u32_true() -> i32 {
+    // CHECK: ret i32 1
+    _u32(1)
+}
+
+// CHECK-LABEL: @_u32_false(
+#[no_mangle]
+pub fn _u32_false(a: u32) -> i32 {
+    // CHECK: ret i32 0
+    _u32(a)
+}
+
+#[inline]
+pub fn _bool(b: bool) -> i32 {
+    if is_val_statically_known(b) { 3 } else { 2 }
+}
+
+// CHECK-LABEL: @_bool_true(
+#[no_mangle]
+pub fn _bool_true() -> i32 {
+    // CHECK: ret i32 3
+    _bool(true)
+}
+
+// CHECK-LABEL: @_bool_false(
+#[no_mangle]
+pub fn _bool_false(b: bool) -> i32 {
+    // CHECK: ret i32 2
+    _bool(b)
+}
+
+#[inline]
+pub fn _iref(a: &u8) -> i32 {
+    if is_val_statically_known(a) { 5 } else { 4 }
+}
+
+// CHECK-LABEL: @_iref_borrow(
+#[no_mangle]
+pub fn _iref_borrow() -> i32 {
+    // CHECK: ret i32 4
+    _iref(&0)
+}
+
+// CHECK-LABEL: @_iref_arg(
+#[no_mangle]
+pub fn _iref_arg(a: &u8) -> i32 {
+    // CHECK: ret i32 4
+    _iref(a)
+}
+
+#[inline]
+pub fn _slice_ref(a: &[u8]) -> i32 {
+    if is_val_statically_known(a) { 7 } else { 6 }
+}
+
+// CHECK-LABEL: @_slice_ref_borrow(
+#[no_mangle]
+pub fn _slice_ref_borrow() -> i32 {
+    // CHECK: ret i32 6
+    _slice_ref(&[0; 3])
+}
+
+// CHECK-LABEL: @_slice_ref_arg(
+#[no_mangle]
+pub fn _slice_ref_arg(a: &[u8]) -> i32 {
+    // CHECK: ret i32 6
+    _slice_ref(a)
+}
+
+#[inline]
+pub fn _f16(a: f16) -> i32 {
+    if is_val_statically_known(a) { 1 } else { 0 }
+}
+
+// CHECK-LABEL: @_f16_true(
+#[no_mangle]
+pub fn _f16_true() -> i32 {
+    // CHECK: ret i32 1
+    _f16(1.0)
+}
+
+// CHECK-LABEL: @_f16_false(
+#[no_mangle]
+pub fn _f16_false(a: f16) -> i32 {
+    // CHECK: ret i32 0
+    _f16(a)
+}
+
+#[inline]
+pub fn _f32(a: f32) -> i32 {
+    if is_val_statically_known(a) { 1 } else { 0 }
+}
+
+// CHECK-LABEL: @_f32_true(
+#[no_mangle]
+pub fn _f32_true() -> i32 {
+    // CHECK: ret i32 1
+    _f32(1.0)
+}
+
+// CHECK-LABEL: @_f32_false(
+#[no_mangle]
+pub fn _f32_false(a: f32) -> i32 {
+    // CHECK: ret i32 0
+    _f32(a)
+}
+
+#[inline]
+pub fn _f64(a: f64) -> i32 {
+    if is_val_statically_known(a) { 1 } else { 0 }
+}
+
+// CHECK-LABEL: @_f64_true(
+#[no_mangle]
+pub fn _f64_true() -> i32 {
+    // CHECK: ret i32 1
+    _f64(1.0)
+}
+
+// CHECK-LABEL: @_f64_false(
+#[no_mangle]
+pub fn _f64_false(a: f64) -> i32 {
+    // CHECK: ret i32 0
+    _f64(a)
+}
+
+#[inline]
+pub fn _f128(a: f128) -> i32 {
+    if is_val_statically_known(a) { 1 } else { 0 }
+}
+
+// CHECK-LABEL: @_f128_true(
+#[no_mangle]
+pub fn _f128_true() -> i32 {
+    // CHECK: ret i32 1
+    _f128(1.0)
+}
+
+// CHECK-LABEL: @_f128_false(
+#[no_mangle]
+pub fn _f128_false(a: f128) -> i32 {
+    // CHECK: ret i32 0
+    _f128(a)
+}
diff --git a/tests/codegen-llvm/issue-97217.rs b/tests/codegen-llvm/issue-97217.rs
new file mode 100644
index 00000000000..ef9acc5fc93
--- /dev/null
+++ b/tests/codegen-llvm/issue-97217.rs
@@ -0,0 +1,20 @@
+//@ compile-flags: -C opt-level=3
+#![crate_type = "lib"]
+
+// Regression test for issue 97217 (the following should result in no allocations)
+
+// CHECK-LABEL: @issue97217
+#[no_mangle]
+pub fn issue97217() -> i32 {
+    // drop_in_place should be inlined and never appear
+    // CHECK-NOT: drop_in_place
+
+    // __rust_alloc should be optimized out
+    // CHECK-NOT: __rust_alloc
+
+    let v1 = vec![5, 6, 7];
+    let v1_iter = v1.iter();
+    let total: i32 = v1_iter.sum();
+    println!("{}", total);
+    total
+}
diff --git a/tests/codegen-llvm/issues/issue-101048.rs b/tests/codegen-llvm/issues/issue-101048.rs
new file mode 100644
index 00000000000..cfe65e758fd
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-101048.rs
@@ -0,0 +1,12 @@
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+
+#[no_mangle]
+pub fn all_zero(data: &[u64]) -> bool {
+    // CHECK-LABEL: @all_zero(
+    // CHECK: [[PHI:%.*]] = phi i1
+    // CHECK-NOT: phi i8
+    // CHECK-NOT: zext
+    data.iter().copied().fold(true, |acc, x| acc & (x == 0))
+}
diff --git a/tests/codegen-llvm/issues/issue-101082.rs b/tests/codegen-llvm/issues/issue-101082.rs
new file mode 100644
index 00000000000..8d15921ddb4
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-101082.rs
@@ -0,0 +1,42 @@
+//@ compile-flags: -Copt-level=3
+//@ revisions: host x86-64 x86-64-v3
+//@ min-llvm-version: 20
+
+//@[host] ignore-x86_64
+
+// Set the base cpu explicitly, in case the default has been changed.
+//@[x86-64] only-x86_64
+//@[x86-64] compile-flags: -Ctarget-cpu=x86-64
+
+// FIXME(cuviper) x86-64-v3 in particular regressed in #131563, and the workaround
+// at the time still sometimes fails, so only verify it for the power-of-two size
+// - https://github.com/llvm/llvm-project/issues/134735
+//@[x86-64-v3] only-x86_64
+//@[x86-64-v3] min-llvm-version: 21
+//@[x86-64-v3] compile-flags: -Ctarget-cpu=x86-64-v3
+
+#![crate_type = "lib"]
+
+#[no_mangle]
+pub fn test() -> usize {
+    // CHECK-LABEL: @test(
+    // CHECK: ret {{i64|i32}} 165
+    let values = [23, 16, 54, 3, 60, 9];
+    let mut acc = 0;
+    for item in values {
+        acc += item;
+    }
+    acc
+}
+
+#[no_mangle]
+pub fn test_eight() -> usize {
+    // CHECK-LABEL: @test_eight(
+    // CHECK: ret {{i64|i32}} 220
+    let values = [23, 16, 54, 3, 60, 9, 13, 42];
+    let mut acc = 0;
+    for item in values {
+        acc += item;
+    }
+    acc
+}
diff --git a/tests/codegen-llvm/issues/issue-101814.rs b/tests/codegen-llvm/issues/issue-101814.rs
new file mode 100644
index 00000000000..668ec8476e8
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-101814.rs
@@ -0,0 +1,18 @@
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+
+#[no_mangle]
+pub fn test(a: [i32; 10]) -> i32 {
+    // CHECK-LABEL: @test(
+    // CHECK: [[L1:%.+]] = load i32
+    // CHECK: [[L2:%.+]] = load i32
+    // CHECK: [[R:%.+]] = add i32 [[L1]], [[L2]]
+    // CHECK: ret i32 [[R]]
+    let mut sum = 0;
+    for v in a.iter().skip(8) {
+        sum += v;
+    }
+
+    sum
+}
diff --git a/tests/codegen-llvm/issues/issue-103132.rs b/tests/codegen-llvm/issues/issue-103132.rs
new file mode 100644
index 00000000000..623cab92806
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-103132.rs
@@ -0,0 +1,15 @@
+//@ compile-flags: -Copt-level=3 -C overflow-checks
+
+#![crate_type = "lib"]
+
+#[no_mangle]
+pub fn test(arr: &[u8], weight: u32) {
+    // CHECK-LABEL: @test(
+    // CHECK-NOT: panic
+    let weight = weight.min(256 * 256 * 256);
+
+    for x in arr {
+        assert!(weight <= 256 * 256 * 256);
+        let result = *x as u32 * weight;
+    }
+}
diff --git a/tests/codegen-llvm/issues/issue-103285-ptr-addr-overflow-check.rs b/tests/codegen-llvm/issues/issue-103285-ptr-addr-overflow-check.rs
new file mode 100644
index 00000000000..3ada5412e83
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-103285-ptr-addr-overflow-check.rs
@@ -0,0 +1,15 @@
+//@ compile-flags: -Copt-level=3 -C debug-assertions=yes
+
+#![crate_type = "lib"]
+
+#[no_mangle]
+pub fn test(src: *const u8, dst: *const u8) -> usize {
+    // CHECK-LABEL: @test(
+    // CHECK-NOT: panic
+    let src_usize = src.addr();
+    let dst_usize = dst.addr();
+    if src_usize > dst_usize {
+        return src_usize - dst_usize;
+    }
+    return 0;
+}
diff --git a/tests/codegen-llvm/issues/issue-103327.rs b/tests/codegen-llvm/issues/issue-103327.rs
new file mode 100644
index 00000000000..4de3cfd12a0
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-103327.rs
@@ -0,0 +1,13 @@
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+
+#[no_mangle]
+pub fn test(a: i32, b: i32) -> bool {
+    // CHECK-LABEL: @test(
+    // CHECK: ret i1 true
+    let c1 = (a >= 0) && (a <= 10);
+    let c2 = (b >= 0) && (b <= 20);
+
+    if c1 & c2 { a + 100 != b } else { true }
+}
diff --git a/tests/codegen-llvm/issues/issue-103840.rs b/tests/codegen-llvm/issues/issue-103840.rs
new file mode 100644
index 00000000000..c6c5098bdd0
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-103840.rs
@@ -0,0 +1,9 @@
+//@ compile-flags: -Copt-level=3
+#![crate_type = "lib"]
+
+pub fn foo(t: &mut Vec<usize>) {
+    // CHECK-NOT: __rust_dealloc
+    let mut taken = std::mem::take(t);
+    taken.pop();
+    *t = taken;
+}
diff --git a/tests/codegen-llvm/issues/issue-105386-ub-in-debuginfo.rs b/tests/codegen-llvm/issues/issue-105386-ub-in-debuginfo.rs
new file mode 100644
index 00000000000..848aa910b58
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-105386-ub-in-debuginfo.rs
@@ -0,0 +1,24 @@
+//@ compile-flags: --crate-type=lib -Copt-level=3 -Cdebuginfo=2 -Cno-prepopulate-passes -Zmir-enable-passes=-ScalarReplacementOfAggregates
+// MIR SROA will decompose the closure
+#![feature(stmt_expr_attributes)]
+
+pub struct S([usize; 8]);
+
+#[no_mangle]
+pub fn outer_function(x: S, y: S) -> usize {
+    (#[inline(always)]
+    || {
+        let _z = x;
+        y.0[0]
+    })()
+}
+
+// Check that we do not attempt to load from the spilled arg before it is assigned to
+// when generating debuginfo.
+// CHECK-LABEL: @outer_function
+// CHECK: [[spill:%.*]] = alloca
+// CHECK-NOT: [[ptr_tmp:%.*]] = getelementptr inbounds i8, ptr [[spill]]
+// CHECK-NOT: [[load:%.*]] = load ptr, ptr
+// CHECK: call void @llvm.lifetime.start{{.*}}({{.*}}, ptr [[spill]])
+// CHECK: [[inner:%.*]] = getelementptr inbounds i8, ptr [[spill]]
+// CHECK: call void @llvm.memcpy{{.*}}(ptr {{align .*}} [[inner]], ptr {{align .*}} %x
diff --git a/tests/codegen-llvm/issues/issue-106369.rs b/tests/codegen-llvm/issues/issue-106369.rs
new file mode 100644
index 00000000000..3583d20c9fa
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-106369.rs
@@ -0,0 +1,14 @@
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+
+// From <https://github.com/rust-lang/rust/issues/106369#issuecomment-1369095304>
+
+// CHECK-LABEL: @issue_106369(
+#[no_mangle]
+pub unsafe fn issue_106369(ptr: *const &i32) -> bool {
+    // CHECK-NOT: icmp
+    // CHECK: ret i1 true
+    // CHECK-NOT: icmp
+    Some(std::ptr::read(ptr)).is_some()
+}
diff --git a/tests/codegen-llvm/issues/issue-107681-unwrap_unchecked.rs b/tests/codegen-llvm/issues/issue-107681-unwrap_unchecked.rs
new file mode 100644
index 00000000000..69aefc6b1fb
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-107681-unwrap_unchecked.rs
@@ -0,0 +1,19 @@
+//@ compile-flags: -Copt-level=3
+
+// Test for #107681.
+// Make sure we don't create `br` or `select` instructions.
+
+#![crate_type = "lib"]
+
+use std::iter::Copied;
+use std::slice::Iter;
+
+#[no_mangle]
+pub unsafe fn foo(x: &mut Copied<Iter<'_, u32>>) -> u32 {
+    // CHECK-LABEL: @foo(
+    // CHECK-NOT: br
+    // CHECK-NOT: select
+    // CHECK: [[RET:%.*]] = load i32, ptr
+    // CHECK-NEXT: ret i32 [[RET]]
+    x.next().unwrap_unchecked()
+}
diff --git a/tests/codegen-llvm/issues/issue-108395-branchy-bool-match.rs b/tests/codegen-llvm/issues/issue-108395-branchy-bool-match.rs
new file mode 100644
index 00000000000..96387e791b0
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-108395-branchy-bool-match.rs
@@ -0,0 +1,27 @@
+//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled
+//! Test for <https://github.com/rust-lang/rust/issues/108395>. Check that
+//! matching on two bools with wildcards does not produce branches.
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @wildcard(
+#[no_mangle]
+pub fn wildcard(a: u16, b: u16, v: u16) -> u16 {
+    // CHECK-NOT: br
+    match (a == v, b == v) {
+        (true, false) => 0,
+        (false, true) => u16::MAX,
+        _ => 1 << 15, // half
+    }
+}
+
+// CHECK-LABEL: @exhaustive(
+#[no_mangle]
+pub fn exhaustive(a: u16, b: u16, v: u16) -> u16 {
+    // CHECK-NOT: br
+    match (a == v, b == v) {
+        (true, false) => 0,
+        (false, true) => u16::MAX,
+        (true, true) => 1 << 15,
+        (false, false) => 1 << 15,
+    }
+}
diff --git a/tests/codegen-llvm/issues/issue-109328-split_first.rs b/tests/codegen-llvm/issues/issue-109328-split_first.rs
new file mode 100644
index 00000000000..26235edfc19
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-109328-split_first.rs
@@ -0,0 +1,16 @@
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @foo
+// CHECK-NEXT: {{.*}}:
+// CHECK-NEXT: getelementptr inbounds
+// CHECK-NEXT: load [[TYPE:i(32|64)]]
+// CHECK-NEXT: icmp eq [[TYPE]]
+// CHECK-NEXT: br i1
+#[no_mangle]
+pub fn foo(input: &mut &[u64]) -> Option<u64> {
+    let (first, rest) = input.split_first()?;
+    *input = rest;
+    Some(*first)
+}
diff --git a/tests/codegen-llvm/issues/issue-110797-enum-jump-same.rs b/tests/codegen-llvm/issues/issue-110797-enum-jump-same.rs
new file mode 100644
index 00000000000..b5f7c08795b
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-110797-enum-jump-same.rs
@@ -0,0 +1,25 @@
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+
+pub enum K {
+    A(Box<[i32]>),
+    B(Box<[u8]>),
+    C(Box<[String]>),
+    D(Box<[u16]>),
+}
+
+// CHECK-LABEL: @get_len
+// CHECK-NEXT: {{.*}}:
+// CHECK-NEXT: getelementptr inbounds
+// CHECK-NEXT: load [[TYPE:i(32|64)]]
+// CHECK-NEXT: ret [[TYPE]]
+#[no_mangle]
+pub fn get_len(arg: &K) -> usize {
+    match arg {
+        K::A(ref lst) => lst.len(),
+        K::B(ref lst) => lst.len(),
+        K::C(ref lst) => lst.len(),
+        K::D(ref lst) => lst.len(),
+    }
+}
diff --git a/tests/codegen-llvm/issues/issue-111603.rs b/tests/codegen-llvm/issues/issue-111603.rs
new file mode 100644
index 00000000000..2ba5a3f876a
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-111603.rs
@@ -0,0 +1,40 @@
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+#![feature(get_mut_unchecked, new_uninit)]
+
+use std::sync::Arc;
+
+// CHECK-LABEL: @new_from_array
+#[no_mangle]
+pub fn new_from_array(x: u64) -> Arc<[u64]> {
+    // Ensure that we only generate one alloca for the array.
+
+    // CHECK: alloca
+    // CHECK-SAME: [8000 x i8]
+    // CHECK-NOT: alloca
+    let array = [x; 1000];
+    Arc::new(array)
+}
+
+// CHECK-LABEL: @new_uninit
+#[no_mangle]
+pub fn new_uninit(x: u64) -> Arc<[u64; 1000]> {
+    // CHECK: call alloc::sync::arcinner_layout_for_value_layout
+    // CHECK-NOT: call alloc::sync::arcinner_layout_for_value_layout
+    let mut arc = Arc::new_uninit();
+    unsafe { Arc::get_mut_unchecked(&mut arc) }.write([x; 1000]);
+    unsafe { arc.assume_init() }
+}
+
+// CHECK-LABEL: @new_uninit_slice
+#[no_mangle]
+pub fn new_uninit_slice(x: u64) -> Arc<[u64]> {
+    // CHECK: call alloc::sync::arcinner_layout_for_value_layout
+    // CHECK-NOT: call alloc::sync::arcinner_layout_for_value_layout
+    let mut arc = Arc::new_uninit_slice(1000);
+    for elem in unsafe { Arc::get_mut_unchecked(&mut arc) } {
+        elem.write(x);
+    }
+    unsafe { arc.assume_init() }
+}
diff --git a/tests/codegen-llvm/issues/issue-112509-slice-get-andthen-get.rs b/tests/codegen-llvm/issues/issue-112509-slice-get-andthen-get.rs
new file mode 100644
index 00000000000..3909b203d08
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-112509-slice-get-andthen-get.rs
@@ -0,0 +1,16 @@
+//@ compile-flags: -Copt-level=3
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @write_u8_variant_a
+// CHECK-NEXT: {{.*}}:
+// CHECK-NEXT: icmp ugt
+// CHECK-NEXT: getelementptr
+// CHECK-NEXT: select i1 {{.+}} null
+// CHECK-NEXT: insertvalue
+// CHECK-NEXT: insertvalue
+// CHECK-NEXT: ret
+#[no_mangle]
+pub fn write_u8_variant_a(bytes: &mut [u8], buf: u8, offset: usize) -> Option<&mut [u8]> {
+    let buf = buf.to_le_bytes();
+    bytes.get_mut(offset..).and_then(|bytes| bytes.get_mut(..buf.len()))
+}
diff --git a/tests/codegen-llvm/issues/issue-113757-bounds-check-after-cmp-max.rs b/tests/codegen-llvm/issues/issue-113757-bounds-check-after-cmp-max.rs
new file mode 100644
index 00000000000..d495adf9980
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-113757-bounds-check-after-cmp-max.rs
@@ -0,0 +1,18 @@
+// in Rust 1.73, -O and opt-level=3 optimizes differently
+//@ compile-flags: -C opt-level=3
+#![crate_type = "lib"]
+
+use std::cmp::max;
+
+// CHECK-LABEL: @foo
+// CHECK-NOT: slice_start_index_len_fail
+// CHECK-NOT: unreachable
+#[no_mangle]
+pub fn foo(v: &mut Vec<u8>, size: usize) -> Option<&mut [u8]> {
+    if v.len() > max(1, size) {
+        let start = v.len() - size;
+        Some(&mut v[start..])
+    } else {
+        None
+    }
+}
diff --git a/tests/codegen-llvm/issues/issue-114312.rs b/tests/codegen-llvm/issues/issue-114312.rs
new file mode 100644
index 00000000000..61355dd5873
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-114312.rs
@@ -0,0 +1,25 @@
+//@ compile-flags: -Copt-level=3
+//@ only-x86_64-unknown-linux-gnu
+
+// We want to check that this function does not mis-optimize to loop jumping.
+
+#![crate_type = "lib"]
+
+#[repr(C)]
+pub enum Expr {
+    Sum,
+    // must have more than usize data
+    Sub(usize, u8),
+}
+
+#[no_mangle]
+pub extern "C" fn issue_114312(expr: Expr) {
+    // CHECK-LABEL: @issue_114312(
+    // CHECK-SAME: byval
+    // CHECK-NEXT: start:
+    // CHECK-NEXT: ret void
+    match expr {
+        Expr::Sum => {}
+        Expr::Sub(_, _) => issue_114312(Expr::Sum),
+    }
+}
diff --git a/tests/codegen-llvm/issues/issue-115385-llvm-jump-threading.rs b/tests/codegen-llvm/issues/issue-115385-llvm-jump-threading.rs
new file mode 100644
index 00000000000..8cabd94f202
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-115385-llvm-jump-threading.rs
@@ -0,0 +1,46 @@
+//@ compile-flags: -Copt-level=3 -Ccodegen-units=1
+
+#![crate_type = "lib"]
+
+#[repr(i64)]
+pub enum Boolean {
+    False = 0,
+    True = 1,
+}
+
+impl Clone for Boolean {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+
+impl Copy for Boolean {}
+
+extern "C" {
+    fn set_value(foo: *mut i64);
+    fn bar();
+}
+
+pub fn foo(x: bool) {
+    let mut foo = core::mem::MaybeUninit::<i64>::uninit();
+    unsafe {
+        set_value(foo.as_mut_ptr());
+    }
+
+    if x {
+        let l1 = unsafe { *foo.as_mut_ptr().cast::<Boolean>() };
+        if matches!(l1, Boolean::False) {
+            unsafe {
+                *foo.as_mut_ptr() = 0;
+            }
+        }
+    }
+
+    let l2 = unsafe { *foo.as_mut_ptr() };
+    if l2 == 2 {
+        // CHECK: call void @bar
+        unsafe {
+            bar();
+        }
+    }
+}
diff --git a/tests/codegen-llvm/issues/issue-116878.rs b/tests/codegen-llvm/issues/issue-116878.rs
new file mode 100644
index 00000000000..daf46c8bb55
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-116878.rs
@@ -0,0 +1,11 @@
+//@ compile-flags: -Copt-level=3
+#![crate_type = "lib"]
+
+/// Make sure no bounds checks are emitted after a `get_unchecked`.
+// CHECK-LABEL: @unchecked_slice_no_bounds_check
+#[no_mangle]
+pub unsafe fn unchecked_slice_no_bounds_check(s: &[u8]) -> u8 {
+    let a = *s.get_unchecked(1);
+    // CHECK-NOT: panic_bounds_check
+    a + s[0]
+}
diff --git a/tests/codegen-llvm/issues/issue-118306.rs b/tests/codegen-llvm/issues/issue-118306.rs
new file mode 100644
index 00000000000..f12dc7cdfe2
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-118306.rs
@@ -0,0 +1,22 @@
+//@ compile-flags: -Copt-level=3
+//@ only-x86_64
+
+// Test for #118306.
+// Make sure we don't create `br` or `select` instructions.
+
+#![crate_type = "lib"]
+
+#[no_mangle]
+pub fn branchy(input: u64) -> u64 {
+    // CHECK-LABEL: @branchy(
+    // CHECK-NEXT:  start:
+    // CHECK-NEXT:    [[_2:%.*]] = and i64 [[INPUT:%.*]], 3
+    // CHECK-NEXT:    [[SWITCH_GEP:%.*]] = getelementptr inbounds{{( nuw)?}} [4 x i64], ptr @switch.table.branchy, i64 0, i64 [[_2]]
+    // CHECK-NEXT:    [[SWITCH_LOAD:%.*]] = load i64, ptr [[SWITCH_GEP]]
+    // CHECK-NEXT:    ret i64 [[SWITCH_LOAD]]
+    match input % 4 {
+        1 | 2 => 1,
+        3 => 2,
+        _ => 0,
+    }
+}
diff --git a/tests/codegen-llvm/issues/issue-118392.rs b/tests/codegen-llvm/issues/issue-118392.rs
new file mode 100644
index 00000000000..07de8d9b237
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-118392.rs
@@ -0,0 +1,10 @@
+//@ compile-flags: -Copt-level=3
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @div2
+// CHECK: ashr i32 %a, 1
+// CHECK-NEXT: ret i32
+#[no_mangle]
+pub fn div2(a: i32) -> i32 {
+    a.div_euclid(2)
+}
diff --git a/tests/codegen-llvm/issues/issue-119422.rs b/tests/codegen-llvm/issues/issue-119422.rs
new file mode 100644
index 00000000000..17ae71605b5
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-119422.rs
@@ -0,0 +1,83 @@
+//! This test checks that compiler don't generate useless compares to zeros
+//! for `NonZero` integer types.
+//!
+//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled
+//@ edition: 2021
+//@ only-64bit (because the LLVM type of i64 for usize shows up)
+#![crate_type = "lib"]
+
+use core::num::NonZero;
+use core::ptr::NonNull;
+
+// CHECK-LABEL: @check_non_null
+#[no_mangle]
+pub fn check_non_null(x: NonNull<u8>) -> bool {
+    // CHECK: ret i1 false
+    x.as_ptr().is_null()
+}
+
+// CHECK-LABEL: @equals_zero_is_false_u8
+#[no_mangle]
+pub fn equals_zero_is_false_u8(x: NonZero<u8>) -> bool {
+    // CHECK-NOT: br
+    // CHECK: ret i1 false
+    // CHECK-NOT: br
+    x.get() == 0
+}
+
+// CHECK-LABEL: @not_equals_zero_is_true_u8
+#[no_mangle]
+pub fn not_equals_zero_is_true_u8(x: NonZero<u8>) -> bool {
+    // CHECK-NOT: br
+    // CHECK: ret i1 true
+    // CHECK-NOT: br
+    x.get() != 0
+}
+
+// CHECK-LABEL: @equals_zero_is_false_i8
+#[no_mangle]
+pub fn equals_zero_is_false_i8(x: NonZero<i8>) -> bool {
+    // CHECK-NOT: br
+    // CHECK: ret i1 false
+    // CHECK-NOT: br
+    x.get() == 0
+}
+
+// CHECK-LABEL: @not_equals_zero_is_true_i8
+#[no_mangle]
+pub fn not_equals_zero_is_true_i8(x: NonZero<i8>) -> bool {
+    // CHECK-NOT: br
+    // CHECK: ret i1 true
+    // CHECK-NOT: br
+    x.get() != 0
+}
+
+// CHECK-LABEL: @usize_try_from_u32
+#[no_mangle]
+pub fn usize_try_from_u32(x: NonZero<u32>) -> NonZero<usize> {
+    // CHECK-NOT: br
+    // CHECK: zext i32 %{{.*}} to i64
+    // CHECK-NOT: br
+    // CHECK: ret i64
+    x.try_into().unwrap()
+}
+
+// CHECK-LABEL: @isize_try_from_i32
+#[no_mangle]
+pub fn isize_try_from_i32(x: NonZero<i32>) -> NonZero<isize> {
+    // CHECK-NOT: br
+    // CHECK: sext i32 %{{.*}} to i64
+    // CHECK-NOT: br
+    // CHECK: ret i64
+    x.try_into().unwrap()
+}
+
+// CHECK-LABEL: @u64_from_nonzero_is_not_zero
+#[no_mangle]
+pub fn u64_from_nonzero_is_not_zero(x: NonZero<u64>) -> bool {
+    // CHECK-NOT: br
+    // CHECK: ret i1 false
+    // CHECK-NOT: br
+    let v: u64 = x.into();
+    v == 0
+}
diff --git a/tests/codegen-llvm/issues/issue-121719-common-field-offset.rs b/tests/codegen-llvm/issues/issue-121719-common-field-offset.rs
new file mode 100644
index 00000000000..9f5f44e0375
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-121719-common-field-offset.rs
@@ -0,0 +1,44 @@
+//! This test checks that match branches which all access a field
+//! at the same offset are merged together.
+//!
+//@ compile-flags: -Copt-level=3
+#![crate_type = "lib"]
+
+#[repr(C)]
+pub struct A {
+    x: f64,
+    y: u64,
+}
+#[repr(C)]
+pub struct B {
+    x: f64,
+    y: u32,
+}
+#[repr(C)]
+pub struct C {
+    x: f64,
+    y: u16,
+}
+#[repr(C)]
+pub struct D {
+    x: f64,
+    y: u8,
+}
+
+pub enum E {
+    A(A),
+    B(B),
+    C(C),
+    D(D),
+}
+
+// CHECK-LABEL: @match_on_e
+#[no_mangle]
+pub fn match_on_e(e: &E) -> &f64 {
+    // CHECK: start:
+    // CHECK-NEXT: getelementptr
+    // CHECK-NEXT: ret
+    match e {
+        E::A(A { x, .. }) | E::B(B { x, .. }) | E::C(C { x, .. }) | E::D(D { x, .. }) => x,
+    }
+}
diff --git a/tests/codegen-llvm/issues/issue-122600-ptr-discriminant-update.rs b/tests/codegen-llvm/issues/issue-122600-ptr-discriminant-update.rs
new file mode 100644
index 00000000000..853a1ff36b1
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-122600-ptr-discriminant-update.rs
@@ -0,0 +1,43 @@
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+
+// The bug here was that it was loading and storing the whole value.
+// It's ok for it to load the discriminant,
+// to preserve the UB from `unreachable_unchecked`,
+// but it better only store the constant discriminant of `B`.
+
+pub enum State {
+    A([u8; 753]),
+    B([u8; 753]),
+}
+
+// CHECK-LABEL: @update
+#[no_mangle]
+pub unsafe fn update(s: *mut State) {
+    // CHECK-NOT: alloca
+
+    // CHECK-NOT: load
+    // CHECK-NOT: store
+    // CHECK-NOT: memcpy
+    // CHECK-NOT: 75{{3|4}}
+
+    // CHECK: %[[TAG:.+]] = load i8, ptr %s, align 1
+    // CHECK-NEXT: trunc nuw i8 %[[TAG]] to i1
+
+    // CHECK-NOT: load
+    // CHECK-NOT: store
+    // CHECK-NOT: memcpy
+    // CHECK-NOT: 75{{3|4}}
+
+    // CHECK: store i8 1, ptr %s, align 1
+
+    // CHECK-NOT: load
+    // CHECK-NOT: store
+    // CHECK-NOT: memcpy
+    // CHECK-NOT: 75{{3|4}}
+
+    // CHECK: ret
+    let State::A(v) = s.read() else { std::hint::unreachable_unchecked() };
+    s.write(State::B(v));
+}
diff --git a/tests/codegen-llvm/issues/issue-123712-str-to-lower-autovectorization.rs b/tests/codegen-llvm/issues/issue-123712-str-to-lower-autovectorization.rs
new file mode 100644
index 00000000000..11ee10e8cc3
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-123712-str-to-lower-autovectorization.rs
@@ -0,0 +1,23 @@
+//@ only-x86_64
+//@ compile-flags: -C opt-level=3
+#![crate_type = "lib"]
+#![no_std]
+#![feature(str_internals)]
+
+extern crate alloc;
+
+/// Ensure that the ascii-prefix loop for `str::to_lowercase` and `str::to_uppercase` uses vector
+/// instructions.
+///
+/// The llvm ir should be the same for all targets that support some form of simd. Only targets
+/// without any simd instructions would see scalarized ir.
+/// Unfortunately, there is no `only-simd` directive to only run this test on only such platforms,
+/// and using test revisions would still require the core libraries for all platforms.
+// CHECK-LABEL: @lower_while_ascii
+// CHECK: [[A:%[0-9]]] = load <16 x i8>
+// CHECK-NEXT: [[B:%[0-9]]] = icmp slt <16 x i8> [[A]], zeroinitializer
+// CHECK-NEXT: [[C:%[0-9]]] = bitcast <16 x i1> [[B]] to i16
+#[no_mangle]
+pub fn lower_while_ascii(s: &str) -> (alloc::string::String, &str) {
+    alloc::str::convert_while_ascii(s, u8::to_ascii_lowercase)
+}
diff --git a/tests/codegen-llvm/issues/issue-126585.rs b/tests/codegen-llvm/issues/issue-126585.rs
new file mode 100644
index 00000000000..466dab64cdc
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-126585.rs
@@ -0,0 +1,23 @@
+//@ compile-flags: -Copt-level=s
+//@ only-x86_64
+
+// Test for #126585.
+// Ensure that this IR doesn't have extra undef phi input, which also guarantees that this asm
+// doesn't have subsequent labels and unnecessary `jmp` instructions.
+
+#![crate_type = "lib"]
+
+#[no_mangle]
+fn checked_div_round(a: u64, b: u64) -> Option<u64> {
+    // CHECK-LABEL: @checked_div_round
+    // CHECK: phi
+    // CHECK-NOT: undef
+    // CHECK: phi
+    // CHECK-NOT: undef
+    match b {
+        0 => None,
+        1 => Some(a),
+        // `a / b` is computable and `(a % b) * 2` can not overflow since `b >= 2`.
+        b => Some(a / b + if (a % b) * 2 >= b { 1 } else { 0 }),
+    }
+}
diff --git a/tests/codegen-llvm/issues/issue-129795.rs b/tests/codegen-llvm/issues/issue-129795.rs
new file mode 100644
index 00000000000..dc64ee35c97
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-129795.rs
@@ -0,0 +1,17 @@
+//@ compile-flags: -Copt-level=3
+//@ min-llvm-version: 20
+#![crate_type = "lib"]
+
+// Ensure that a modulo operation with an operand that is known to be
+// a power-of-two is properly optimized.
+
+// CHECK-LABEL: @modulo_with_power_of_two_divisor
+// CHECK: add i64 %divisor, -1
+// CHECK-NEXT: and i64
+// CHECK-NEXT: ret i64
+#[no_mangle]
+pub fn modulo_with_power_of_two_divisor(dividend: u64, divisor: u64) -> u64 {
+    assert!(divisor.is_power_of_two());
+    // should be optimized to (dividend & (divisor - 1))
+    dividend % divisor
+}
diff --git a/tests/codegen-llvm/issues/issue-13018.rs b/tests/codegen-llvm/issues/issue-13018.rs
new file mode 100644
index 00000000000..8040018b931
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-13018.rs
@@ -0,0 +1,14 @@
+//@ compile-flags: -Copt-level=3
+
+// A drop([...].clone()) sequence on an Rc should be a no-op
+// In particular, no call to __rust_dealloc should be emitted
+//
+// We use a cdylib since it's a leaf unit for Rust purposes, so doesn't codegen -Zshare-generics
+// code.
+#![crate_type = "cdylib"]
+use std::rc::Rc;
+
+pub fn foo(t: &Rc<Vec<usize>>) {
+    // CHECK-NOT: __rust_dealloc
+    drop(t.clone());
+}
diff --git a/tests/codegen-llvm/issues/issue-136329-optnone-noinline.rs b/tests/codegen-llvm/issues/issue-136329-optnone-noinline.rs
new file mode 100644
index 00000000000..57c9e47a499
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-136329-optnone-noinline.rs
@@ -0,0 +1,21 @@
+//! Ensure that `#[optimize(none)]` functions are never inlined
+
+//@ compile-flags: -Copt-level=3
+
+#![feature(optimize_attribute)]
+
+#[optimize(none)]
+pub fn foo() {
+    let _x = 123;
+}
+
+// CHECK-LABEL: define{{.*}}void @bar
+// CHECK: start:
+// CHECK: {{.*}}call {{.*}}void
+// CHECK: ret void
+#[no_mangle]
+pub fn bar() {
+    foo();
+}
+
+fn main() {}
diff --git a/tests/codegen-llvm/issues/issue-15953.rs b/tests/codegen-llvm/issues/issue-15953.rs
new file mode 100644
index 00000000000..70e597ac1dd
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-15953.rs
@@ -0,0 +1,29 @@
+// Test that llvm generates `memcpy` for moving a value
+// inside a function and moving an argument.
+
+struct Foo {
+    x: Vec<i32>,
+}
+
+#[inline(never)]
+#[no_mangle]
+// CHECK: memcpy
+fn interior(x: Vec<i32>) -> Vec<i32> {
+    let Foo { x } = Foo { x };
+    x
+}
+
+#[inline(never)]
+#[no_mangle]
+// CHECK: memcpy
+fn exterior(x: Vec<i32>) -> Vec<i32> {
+    x
+}
+
+fn main() {
+    let x = interior(Vec::new());
+    println!("{:?}", x);
+
+    let x = exterior(Vec::new());
+    println!("{:?}", x);
+}
diff --git a/tests/codegen-llvm/issues/issue-27130.rs b/tests/codegen-llvm/issues/issue-27130.rs
new file mode 100644
index 00000000000..594e02af097
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-27130.rs
@@ -0,0 +1,21 @@
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @trim_in_place
+#[no_mangle]
+pub fn trim_in_place(a: &mut &[u8]) {
+    while a.first() == Some(&42) {
+        // CHECK-NOT: slice_index_order_fail
+        *a = &a[1..];
+    }
+}
+
+// CHECK-LABEL: @trim_in_place2
+#[no_mangle]
+pub fn trim_in_place2(a: &mut &[u8]) {
+    while let Some(&42) = a.first() {
+        // CHECK-NOT: slice_index_order_fail
+        *a = &a[2..];
+    }
+}
diff --git a/tests/codegen-llvm/issues/issue-32031.rs b/tests/codegen-llvm/issues/issue-32031.rs
new file mode 100644
index 00000000000..559e8d947fb
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-32031.rs
@@ -0,0 +1,29 @@
+//@ compile-flags: -C no-prepopulate-passes -Copt-level=0
+// 32-bit x86 returns `f32` and `f64` differently to avoid the x87 stack.
+//@ revisions: x86 other
+//@[x86] only-rustc_abi-x86-sse2
+//@[other] ignore-x86
+
+#![crate_type = "lib"]
+
+#[no_mangle]
+pub struct F32(f32);
+
+// other: define{{.*}}float @add_newtype_f32(float %a, float %b)
+// x86: define{{.*}}<4 x i8> @add_newtype_f32(float %a, float %b)
+#[inline(never)]
+#[no_mangle]
+pub fn add_newtype_f32(a: F32, b: F32) -> F32 {
+    F32(a.0 + b.0)
+}
+
+#[no_mangle]
+pub struct F64(f64);
+
+// other: define{{.*}}double @add_newtype_f64(double %a, double %b)
+// x86: define{{.*}}<8 x i8> @add_newtype_f64(double %a, double %b)
+#[inline(never)]
+#[no_mangle]
+pub fn add_newtype_f64(a: F64, b: F64) -> F64 {
+    F64(a.0 + b.0)
+}
diff --git a/tests/codegen-llvm/issues/issue-32364.rs b/tests/codegen-llvm/issues/issue-32364.rs
new file mode 100644
index 00000000000..016981d1947
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-32364.rs
@@ -0,0 +1,17 @@
+// Test that `extern "stdcall"` is properly translated.
+
+//@ only-x86
+
+//@ compile-flags: -C no-prepopulate-passes
+
+struct Foo;
+
+impl Foo {
+    // CHECK: define internal x86_stdcallcc void @{{.*}}foo{{.*}}()
+    #[inline(never)]
+    pub extern "stdcall" fn foo<T>() {}
+}
+
+fn main() {
+    Foo::foo::<Foo>();
+}
diff --git a/tests/codegen-llvm/issues/issue-34634.rs b/tests/codegen-llvm/issues/issue-34634.rs
new file mode 100644
index 00000000000..d32fa97ec38
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-34634.rs
@@ -0,0 +1,16 @@
+// Test that `wrapping_div` only checks divisor once.
+// This test checks that there is only a single compare against -1 and -1 is not present as a
+// switch case (the second check present until rustc 1.12).
+// This test also verifies that a single panic call is generated (for the division by zero case).
+
+//@ compile-flags: -Copt-level=3
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @f
+#[no_mangle]
+pub fn f(x: i32, y: i32) -> i32 {
+    // CHECK-COUNT-1: icmp eq i32 %y, -1
+    // CHECK-COUNT-1: panic
+    // CHECK-NOT: i32 -1, label
+    x.wrapping_div(y)
+}
diff --git a/tests/codegen-llvm/issues/issue-34947-pow-i32.rs b/tests/codegen-llvm/issues/issue-34947-pow-i32.rs
new file mode 100644
index 00000000000..b4750cd35bc
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-34947-pow-i32.rs
@@ -0,0 +1,13 @@
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @issue_34947
+#[no_mangle]
+pub fn issue_34947(x: i32) -> i32 {
+    // CHECK: mul
+    // CHECK-NEXT: mul
+    // CHECK-NEXT: mul
+    // CHECK-NEXT: ret
+    x.pow(5)
+}
diff --git a/tests/codegen-llvm/issues/issue-36010-some-box-is_some.rs b/tests/codegen-llvm/issues/issue-36010-some-box-is_some.rs
new file mode 100644
index 00000000000..c9a8262162d
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-36010-some-box-is_some.rs
@@ -0,0 +1,28 @@
+#![crate_type = "lib"]
+
+//@ compile-flags: -Copt-level=3
+
+use std::mem;
+
+fn foo<T>(a: &mut T, b: T) -> bool {
+    let b = Some(mem::replace(a, b));
+    let ret = b.is_some();
+    mem::forget(b);
+    return ret;
+}
+
+// CHECK-LABEL: @foo_u32
+// CHECK: store i32
+// CHECK-NEXT: ret i1 true
+#[no_mangle]
+pub fn foo_u32(a: &mut u32, b: u32) -> bool {
+    foo(a, b)
+}
+
+// CHECK-LABEL: @foo_box
+// CHECK: store ptr
+// CHECK-NEXT: ret i1 true
+#[no_mangle]
+pub fn foo_box(a: &mut Box<u32>, b: Box<u32>) -> bool {
+    foo(a, b)
+}
diff --git a/tests/codegen-llvm/issues/issue-37945.rs b/tests/codegen-llvm/issues/issue-37945.rs
new file mode 100644
index 00000000000..23d0eab8ae4
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-37945.rs
@@ -0,0 +1,34 @@
+//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled
+//@ ignore-32bit LLVM has a bug with them
+
+// Check that LLVM understands that `Iter` pointer is not null. Issue #37945.
+
+#![crate_type = "lib"]
+
+use std::slice::Iter;
+
+#[no_mangle]
+pub fn is_empty_1(xs: Iter<f32>) -> bool {
+    // CHECK-LABEL: @is_empty_1(
+    // CHECK-NEXT:  start:
+    // CHECK-NEXT:    [[A:%.*]] = icmp ne ptr {{%xs.0|%xs.1}}, null
+    // CHECK-NEXT:    tail call void @llvm.assume(i1 [[A]])
+    // The order between %xs.0 and %xs.1 on the next line doesn't matter
+    // and different LLVM versions produce different order.
+    // CHECK-NEXT:    [[B:%.*]] = icmp eq ptr {{%xs.0, %xs.1|%xs.1, %xs.0}}
+    // CHECK-NEXT:    ret i1 [[B:%.*]]
+    { xs }.next().is_none()
+}
+
+#[no_mangle]
+pub fn is_empty_2(xs: Iter<f32>) -> bool {
+    // CHECK-LABEL: @is_empty_2
+    // CHECK-NEXT:  start:
+    // CHECK-NEXT:    [[C:%.*]] = icmp ne ptr {{%xs.0|%xs.1}}, null
+    // CHECK-NEXT:    tail call void @llvm.assume(i1 [[C]])
+    // The order between %xs.0 and %xs.1 on the next line doesn't matter
+    // and different LLVM versions produce different order.
+    // CHECK-NEXT:    [[D:%.*]] = icmp eq ptr {{%xs.0, %xs.1|%xs.1, %xs.0}}
+    // CHECK-NEXT:    ret i1 [[D:%.*]]
+    xs.map(|&x| x).next().is_none()
+}
diff --git a/tests/codegen-llvm/issues/issue-45222.rs b/tests/codegen-llvm/issues/issue-45222.rs
new file mode 100644
index 00000000000..0201363c41a
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-45222.rs
@@ -0,0 +1,62 @@
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+
+// verify that LLVM recognizes a loop involving 0..=n and will const-fold it.
+
+// Example from original issue #45222
+
+fn foo2(n: u64) -> u64 {
+    let mut count = 0;
+    for _ in 0..n {
+        for j in (0..=n).rev() {
+            count += j;
+        }
+    }
+    count
+}
+
+// CHECK-LABEL: @check_foo2
+#[no_mangle]
+pub fn check_foo2() -> u64 {
+    // CHECK: ret i64 500005000000000
+    foo2(100000)
+}
+
+// Simplified example of #45222
+//
+// Temporarily disabled in #68835 to fix a soundness hole.
+//
+// fn triangle_inc(n: u64) -> u64 {
+//     let mut count = 0;
+//     for j in 0 ..= n {
+//         count += j;
+//     }
+//     count
+// }
+//
+// // COMMENTEDCHECK-LABEL: @check_triangle_inc
+// #[no_mangle]
+// pub fn check_triangle_inc() -> u64 {
+//     // COMMENTEDCHECK: ret i64 5000050000
+//     triangle_inc(100000)
+// }
+
+// Demo in #48012
+
+fn foo3r(n: u64) -> u64 {
+    let mut count = 0;
+    (0..n).for_each(|_| {
+        (0..=n).rev().for_each(|j| {
+            count += j;
+        })
+    });
+    count
+}
+
+// CHECK-LABEL: @check_foo3r
+#[no_mangle]
+pub fn check_foo3r() -> u64 {
+    // CHECK: ret i64 500050000000
+    foo3r(10000)
+}
diff --git a/tests/codegen-llvm/issues/issue-45466.rs b/tests/codegen-llvm/issues/issue-45466.rs
new file mode 100644
index 00000000000..164a27ef5d4
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-45466.rs
@@ -0,0 +1,14 @@
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "rlib"]
+
+// CHECK-LABEL: @memzero
+// CHECK-NOT: store
+// CHECK: call void @llvm.memset
+// CHECK-NOT: store
+#[no_mangle]
+pub fn memzero(data: &mut [u8]) {
+    for i in 0..data.len() {
+        data[i] = 0;
+    }
+}
diff --git a/tests/codegen-llvm/issues/issue-45964-bounds-check-slice-pos.rs b/tests/codegen-llvm/issues/issue-45964-bounds-check-slice-pos.rs
new file mode 100644
index 00000000000..a48bb2a1ccf
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-45964-bounds-check-slice-pos.rs
@@ -0,0 +1,38 @@
+// This test case checks that slice::{r}position functions do not
+// prevent optimizing away bounds checks
+
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "rlib"]
+
+// CHECK-LABEL: @test
+#[no_mangle]
+pub fn test(y: &[u32], x: &u32, z: &u32) -> bool {
+    let result = match y.iter().position(|a| a == x) {
+        Some(p) => Ok(p),
+        None => Err(()),
+    };
+
+    if let Ok(p) = result {
+        // CHECK-NOT: panic
+        y[p] == *z
+    } else {
+        false
+    }
+}
+
+// CHECK-LABEL: @rtest
+#[no_mangle]
+pub fn rtest(y: &[u32], x: &u32, z: &u32) -> bool {
+    let result = match y.iter().rposition(|a| a == x) {
+        Some(p) => Ok(p),
+        None => Err(()),
+    };
+
+    if let Ok(p) = result {
+        // CHECK-NOT: panic
+        y[p] == *z
+    } else {
+        false
+    }
+}
diff --git a/tests/codegen-llvm/issues/issue-47278.rs b/tests/codegen-llvm/issues/issue-47278.rs
new file mode 100644
index 00000000000..4f0a5bdf36f
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-47278.rs
@@ -0,0 +1,11 @@
+// -C no-prepopulate-passes
+#![crate_type = "staticlib"]
+
+#[repr(C)]
+pub struct Foo(u64);
+
+// CHECK: define {{.*}} @foo(
+#[no_mangle]
+pub extern "C" fn foo(_: Foo) -> Foo {
+    loop {}
+}
diff --git a/tests/codegen-llvm/issues/issue-47442.rs b/tests/codegen-llvm/issues/issue-47442.rs
new file mode 100644
index 00000000000..445234e55ad
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-47442.rs
@@ -0,0 +1,22 @@
+// check that we don't emit unneeded `resume` cleanup blocks for every
+// destructor.
+
+// CHECK-NOT: Unwind
+
+#![feature(test)]
+#![crate_type = "rlib"]
+
+extern crate test;
+
+struct Foo {}
+
+impl Drop for Foo {
+    fn drop(&mut self) {
+        test::black_box(());
+    }
+}
+
+#[no_mangle]
+pub fn foo() {
+    let _foo = Foo {};
+}
diff --git a/tests/codegen-llvm/issues/issue-56267-2.rs b/tests/codegen-llvm/issues/issue-56267-2.rs
new file mode 100644
index 00000000000..98e3732777e
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-56267-2.rs
@@ -0,0 +1,18 @@
+//@ compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "rlib"]
+
+#[allow(dead_code)]
+pub struct Foo<T> {
+    foo: u64,
+    bar: T,
+}
+
+// The load from bar.1 should have alignment 4. Not checking
+// other loads here, as the alignment will be platform-dependent.
+
+// CHECK: %{{.+}} = load i32, ptr %{{.+}}, align 4
+#[no_mangle]
+pub fn test(x: Foo<(i32, i32)>) -> (i32, i32) {
+    x.bar
+}
diff --git a/tests/codegen-llvm/issues/issue-56267.rs b/tests/codegen-llvm/issues/issue-56267.rs
new file mode 100644
index 00000000000..cabcc298482
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-56267.rs
@@ -0,0 +1,18 @@
+//@ compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "rlib"]
+
+#[allow(dead_code)]
+pub struct Foo<T> {
+    foo: u64,
+    bar: T,
+}
+
+// The store writing to bar.1 should have alignment 4. Not checking
+// other stores here, as the alignment will be platform-dependent.
+
+// CHECK: store i32 [[TMP1:%.+]], ptr [[TMP2:%.+]], align 4
+#[no_mangle]
+pub fn test(x: (i32, i32)) -> Foo<(i32, i32)> {
+    Foo { foo: 0, bar: x }
+}
diff --git a/tests/codegen-llvm/issues/issue-56927.rs b/tests/codegen-llvm/issues/issue-56927.rs
new file mode 100644
index 00000000000..415ef073e03
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-56927.rs
@@ -0,0 +1,46 @@
+//@ compile-flags: -C no-prepopulate-passes
+// 32bit MSVC does not align things properly so we suppress high alignment annotations (#112480)
+//@ ignore-i686-pc-windows-msvc
+//@ ignore-i686-pc-windows-gnu
+
+#![crate_type = "rlib"]
+
+#[repr(align(16))]
+pub struct S {
+    arr: [u32; 4],
+}
+
+// CHECK-LABEL: @test1
+// CHECK: store i32 0, ptr %{{.+}}, align 16
+// CHECK: store i32 1, ptr %{{.+}}, align 4
+// CHECK: store i32 2, ptr %{{.+}}, align 8
+// CHECK: store i32 3, ptr %{{.+}}, align 4
+#[no_mangle]
+pub fn test1(s: &mut S) {
+    s.arr[0] = 0;
+    s.arr[1] = 1;
+    s.arr[2] = 2;
+    s.arr[3] = 3;
+}
+
+// CHECK-LABEL: @test2
+// CHECK: store i32 4, ptr %{{.+}}, align 4
+#[allow(unconditional_panic)]
+#[no_mangle]
+pub fn test2(s: &mut S) {
+    s.arr[usize::MAX / 4 + 1] = 4;
+}
+
+// CHECK-LABEL: @test3
+// CHECK: store i32 5, ptr %{{.+}}, align 4
+#[no_mangle]
+pub fn test3(s: &mut S, i: usize) {
+    s.arr[i] = 5;
+}
+
+// CHECK-LABEL: @test4
+// CHECK: store i32 6, ptr %{{.+}}, align 4
+#[no_mangle]
+pub fn test4(s: &mut S) {
+    s.arr = [6; 4];
+}
diff --git a/tests/codegen-llvm/issues/issue-58881.rs b/tests/codegen-llvm/issues/issue-58881.rs
new file mode 100644
index 00000000000..ba6285f3972
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-58881.rs
@@ -0,0 +1,20 @@
+//@ compile-flags: -C no-prepopulate-passes -Copt-level=0
+//
+//@ only-x86_64
+
+#![crate_type = "lib"]
+
+extern "C" {
+    fn variadic_fn(_: i32, ...);
+}
+
+#[repr(C)]
+struct Foo(u8);
+#[repr(C)]
+struct Bar(u64, u64, u64);
+
+// Ensure that emit arguments of the correct type.
+pub unsafe fn test_call_variadic() {
+    // CHECK: call void (i32, ...) @variadic_fn(i32 0, i8 {{.*}}, ptr {{.*}})
+    variadic_fn(0, Foo(0), Bar(0, 0, 0))
+}
diff --git a/tests/codegen-llvm/issues/issue-59352.rs b/tests/codegen-llvm/issues/issue-59352.rs
new file mode 100644
index 00000000000..cb4383d4a30
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-59352.rs
@@ -0,0 +1,18 @@
+// This test is a mirror of mir-opt/issues/issue-59352.rs. The LLVM inliner doesn't inline
+// `char::method::is_digit()` and `char::method::to_digit()`, probably because of their size.
+//
+// Currently, the MIR optimizer isn't capable of removing the unreachable panic in this test case.
+// Once the optimizer can do that, mir-opt/issues/issue-59352.rs will need to be updated and this
+// test case should be removed as it will become redundant.
+
+// mir-opt-level=3 enables inlining and enables LLVM to optimize away the unreachable panic call.
+//@ compile-flags: -Copt-level=3 -Z mir-opt-level=3
+
+#![crate_type = "rlib"]
+
+// CHECK-LABEL: @num_to_digit
+#[no_mangle]
+pub fn num_to_digit(num: char) -> u32 {
+    // CHECK-NOT: panic
+    if num.is_digit(8) { num.to_digit(8).unwrap() } else { 0 }
+}
diff --git a/tests/codegen-llvm/issues/issue-64219-fn-ptr-call-returning-never-is-noreturn.rs b/tests/codegen-llvm/issues/issue-64219-fn-ptr-call-returning-never-is-noreturn.rs
new file mode 100644
index 00000000000..86d020e1751
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-64219-fn-ptr-call-returning-never-is-noreturn.rs
@@ -0,0 +1,19 @@
+//! Test for https://github.com/rust-lang/rust/issues/64219
+//! Check if `noreturn` attribute is applied on calls to
+//! function pointers returning `!` (never type).
+
+#![crate_type = "lib"]
+
+extern "C" {
+    static FOO: fn() -> !;
+}
+
+// CHECK-LABEL: @foo
+#[no_mangle]
+pub unsafe fn foo() {
+    // CHECK: call
+    // CHECK-SAME: [[NUM:#[0-9]+$]]
+    FOO();
+}
+
+// CHECK: attributes [[NUM]] = {{{.*}} noreturn {{.*}}}
diff --git a/tests/codegen-llvm/issues/issue-68667-unwrap-combinators.rs b/tests/codegen-llvm/issues/issue-68667-unwrap-combinators.rs
new file mode 100644
index 00000000000..7f4a32109fe
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-68667-unwrap-combinators.rs
@@ -0,0 +1,15 @@
+#![crate_type = "lib"]
+
+//@ compile-flags: -Copt-level=3
+
+// MIR inlining now optimizes this code.
+
+// CHECK-LABEL: @unwrap_combinators
+// CHECK: {{icmp|trunc}}
+// CHECK-NEXT: icmp
+// CHECK-NEXT: select i1
+// CHECK-NEXT: ret i1
+#[no_mangle]
+pub fn unwrap_combinators(a: Option<i32>, b: i32) -> bool {
+    a.map(|t| t >= b).unwrap_or(false)
+}
diff --git a/tests/codegen-llvm/issues/issue-69101-bounds-check.rs b/tests/codegen-llvm/issues/issue-69101-bounds-check.rs
new file mode 100644
index 00000000000..953b79aa263
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-69101-bounds-check.rs
@@ -0,0 +1,42 @@
+//@ compile-flags: -Copt-level=3
+#![crate_type = "lib"]
+
+// Make sure no bounds checks are emitted in the loop when upfront slicing
+// ensures that the slices are big enough.
+// In particular, bounds checks were not always optimized out if the upfront
+// check was for a greater len than the loop requires.
+// (i.e. `already_sliced_no_bounds_check` was not always optimized even when
+// `already_sliced_no_bounds_check_exact` was)
+// CHECK-LABEL: @already_sliced_no_bounds_check
+#[no_mangle]
+pub fn already_sliced_no_bounds_check(a: &[u8], b: &[u8], c: &mut [u8]) {
+    // CHECK: slice_end_index_len_fail
+    // CHECK-NOT: panic_bounds_check
+    let _ = (&a[..2048], &b[..2048], &mut c[..2048]);
+    for i in 0..1024 {
+        c[i] = a[i] ^ b[i];
+    }
+}
+
+// CHECK-LABEL: @already_sliced_no_bounds_check_exact
+#[no_mangle]
+pub fn already_sliced_no_bounds_check_exact(a: &[u8], b: &[u8], c: &mut [u8]) {
+    // CHECK: slice_end_index_len_fail
+    // CHECK-NOT: panic_bounds_check
+    let _ = (&a[..1024], &b[..1024], &mut c[..1024]);
+    for i in 0..1024 {
+        c[i] = a[i] ^ b[i];
+    }
+}
+
+// Make sure we're checking for the right thing: there can be a panic if the slice is too small.
+// CHECK-LABEL: @already_sliced_bounds_check
+#[no_mangle]
+pub fn already_sliced_bounds_check(a: &[u8], b: &[u8], c: &mut [u8]) {
+    // CHECK: slice_end_index_len_fail
+    // CHECK: panic_bounds_check
+    let _ = (&a[..1023], &b[..2048], &mut c[..2048]);
+    for i in 0..1024 {
+        c[i] = a[i] ^ b[i];
+    }
+}
diff --git a/tests/codegen-llvm/issues/issue-73031.rs b/tests/codegen-llvm/issues/issue-73031.rs
new file mode 100644
index 00000000000..80dea9b5bc2
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-73031.rs
@@ -0,0 +1,22 @@
+//@ compile-flags: -Copt-level=3
+#![crate_type = "lib"]
+
+// Test that LLVM can eliminate the unreachable `All::None` branch.
+
+pub enum All {
+    None,
+    Foo,
+    Bar,
+}
+
+// CHECK-LABEL: @issue_73031
+#[no_mangle]
+pub fn issue_73031(a: &mut All, q: i32) -> i32 {
+    *a = if q == 5 { All::Foo } else { All::Bar };
+    match *a {
+        // CHECK-NOT: panic
+        All::None => panic!(),
+        All::Foo => 1,
+        All::Bar => 2,
+    }
+}
diff --git a/tests/codegen-llvm/issues/issue-73258.rs b/tests/codegen-llvm/issues/issue-73258.rs
new file mode 100644
index 00000000000..936a7554496
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-73258.rs
@@ -0,0 +1,40 @@
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+
+// Adapted from <https://github.com/rust-lang/rust/issues/73258#issue-637346014>
+
+#[derive(Clone, Copy)]
+#[repr(u8)]
+pub enum Foo {
+    A,
+    B,
+    C,
+    D,
+}
+
+// CHECK-LABEL: @issue_73258(
+#[no_mangle]
+pub unsafe fn issue_73258(ptr: *const Foo) -> Foo {
+    // CHECK-NOT: icmp
+    // CHECK-NOT: call
+    // CHECK-NOT: br
+    // CHECK-NOT: select
+
+    // CHECK: %[[R:.+]] = load i8
+    // CHECK-SAME: !range !
+
+    // CHECK-NOT: icmp
+    // CHECK-NOT: call
+    // CHECK-NOT: br
+    // CHECK-NOT: select
+
+    // CHECK: ret i8 %[[R]]
+
+    // CHECK-NOT: icmp
+    // CHECK-NOT: call
+    // CHECK-NOT: br
+    // CHECK-NOT: select
+    let k: Option<Foo> = Some(ptr.read());
+    return k.unwrap();
+}
diff --git a/tests/codegen-llvm/issues/issue-73338-effecient-cmp.rs b/tests/codegen-llvm/issues/issue-73338-effecient-cmp.rs
new file mode 100644
index 00000000000..71641a5457b
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-73338-effecient-cmp.rs
@@ -0,0 +1,39 @@
+// This test checks that comparison operation
+// generated by #[derive(PartialOrd)]
+// doesn't contain jumps for C enums
+
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+
+#[repr(u32)]
+#[derive(Copy, Clone, Eq, PartialEq, PartialOrd)]
+pub enum Foo {
+    Zero,
+    One,
+    Two,
+}
+
+#[no_mangle]
+pub fn compare_less(a: Foo, b: Foo) -> bool {
+    // CHECK-NOT: br {{.*}}
+    a < b
+}
+
+#[no_mangle]
+pub fn compare_le(a: Foo, b: Foo) -> bool {
+    // CHECK-NOT: br {{.*}}
+    a <= b
+}
+
+#[no_mangle]
+pub fn compare_ge(a: Foo, b: Foo) -> bool {
+    // CHECK-NOT: br {{.*}}
+    a >= b
+}
+
+#[no_mangle]
+pub fn compare_greater(a: Foo, b: Foo) -> bool {
+    // CHECK-NOT: br {{.*}}
+    a > b
+}
diff --git a/tests/codegen-llvm/issues/issue-73396-bounds-check-after-position.rs b/tests/codegen-llvm/issues/issue-73396-bounds-check-after-position.rs
new file mode 100644
index 00000000000..1e2c25babe0
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-73396-bounds-check-after-position.rs
@@ -0,0 +1,70 @@
+//@ compile-flags: -Copt-level=3
+#![crate_type = "lib"]
+
+// Make sure no bounds checks are emitted when slicing or indexing
+// with an index from `position()` or `rposition()`.
+
+// CHECK-LABEL: @position_slice_to_no_bounds_check
+#[no_mangle]
+pub fn position_slice_to_no_bounds_check(s: &[u8]) -> &[u8] {
+    // CHECK-NOT: panic
+    // CHECK-NOT: slice_start_index_len_fail
+    // CHECK-NOT: slice_end_index_len_fail
+    // CHECK-NOT: panic_bounds_check
+    // CHECK-NOT: unreachable
+    if let Some(idx) = s.iter().position(|b| *b == b'\\') { &s[..idx] } else { s }
+}
+
+// CHECK-LABEL: @position_slice_from_no_bounds_check
+#[no_mangle]
+pub fn position_slice_from_no_bounds_check(s: &[u8]) -> &[u8] {
+    // CHECK-NOT: panic
+    // CHECK-NOT: slice_start_index_len_fail
+    // CHECK-NOT: slice_end_index_len_fail
+    // CHECK-NOT: panic_bounds_check
+    // CHECK-NOT: unreachable
+    if let Some(idx) = s.iter().position(|b| *b == b'\\') { &s[idx..] } else { s }
+}
+
+// CHECK-LABEL: @position_index_no_bounds_check
+#[no_mangle]
+pub fn position_index_no_bounds_check(s: &[u8]) -> u8 {
+    // CHECK-NOT: panic
+    // CHECK-NOT: slice_start_index_len_fail
+    // CHECK-NOT: slice_end_index_len_fail
+    // CHECK-NOT: panic_bounds_check
+    // CHECK-NOT: unreachable
+    if let Some(idx) = s.iter().position(|b| *b == b'\\') { s[idx] } else { 42 }
+}
+// CHECK-LABEL: @rposition_slice_to_no_bounds_check
+#[no_mangle]
+pub fn rposition_slice_to_no_bounds_check(s: &[u8]) -> &[u8] {
+    // CHECK-NOT: panic
+    // CHECK-NOT: slice_start_index_len_fail
+    // CHECK-NOT: slice_end_index_len_fail
+    // CHECK-NOT: panic_bounds_check
+    // CHECK-NOT: unreachable
+    if let Some(idx) = s.iter().rposition(|b| *b == b'\\') { &s[..idx] } else { s }
+}
+
+// CHECK-LABEL: @rposition_slice_from_no_bounds_check
+#[no_mangle]
+pub fn rposition_slice_from_no_bounds_check(s: &[u8]) -> &[u8] {
+    // CHECK-NOT: panic
+    // CHECK-NOT: slice_start_index_len_fail
+    // CHECK-NOT: slice_end_index_len_fail
+    // CHECK-NOT: panic_bounds_check
+    // CHECK-NOT: unreachable
+    if let Some(idx) = s.iter().rposition(|b| *b == b'\\') { &s[idx..] } else { s }
+}
+
+// CHECK-LABEL: @rposition_index_no_bounds_check
+#[no_mangle]
+pub fn rposition_index_no_bounds_check(s: &[u8]) -> u8 {
+    // CHECK-NOT: panic
+    // CHECK-NOT: slice_start_index_len_fail
+    // CHECK-NOT: slice_end_index_len_fail
+    // CHECK-NOT: panic_bounds_check
+    // CHECK-NOT: unreachable
+    if let Some(idx) = s.iter().rposition(|b| *b == b'\\') { s[idx] } else { 42 }
+}
diff --git a/tests/codegen-llvm/issues/issue-73827-bounds-check-index-in-subexpr.rs b/tests/codegen-llvm/issues/issue-73827-bounds-check-index-in-subexpr.rs
new file mode 100644
index 00000000000..e9dd0d1bf23
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-73827-bounds-check-index-in-subexpr.rs
@@ -0,0 +1,17 @@
+// This test checks that bounds checks are elided when
+// index is part of a (x | y) < C style condition
+
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @get
+#[no_mangle]
+pub fn get(array: &[u8; 8], x: usize, y: usize) -> u8 {
+    if x > 7 || y > 7 {
+        0
+    } else {
+        // CHECK-NOT: panic_bounds_check
+        array[y]
+    }
+}
diff --git a/tests/codegen-llvm/issues/issue-74938-array-split-at.rs b/tests/codegen-llvm/issues/issue-74938-array-split-at.rs
new file mode 100644
index 00000000000..9d3e23d642b
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-74938-array-split-at.rs
@@ -0,0 +1,14 @@
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+
+const N: usize = 3;
+pub type T = u8;
+
+// CHECK-LABEL: @split_multiple
+// CHECK-NOT: unreachable
+#[no_mangle]
+pub fn split_multiple(slice: &[T]) -> (&[T], &[T]) {
+    let len = slice.len() / N;
+    slice.split_at(len * N)
+}
diff --git a/tests/codegen-llvm/issues/issue-75525-bounds-checks.rs b/tests/codegen-llvm/issues/issue-75525-bounds-checks.rs
new file mode 100644
index 00000000000..5dfbd350010
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-75525-bounds-checks.rs
@@ -0,0 +1,26 @@
+// Regression test for #75525, verifies that no bounds checks are generated.
+
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @f0
+// CHECK-NOT: panic
+#[no_mangle]
+pub fn f0(idx: usize, buf: &[u8; 10]) -> u8 {
+    if idx < 8 { buf[idx + 1] } else { 0 }
+}
+
+// CHECK-LABEL: @f1
+// CHECK-NOT: panic
+#[no_mangle]
+pub fn f1(idx: usize, buf: &[u8; 10]) -> u8 {
+    if idx > 5 && idx < 8 { buf[idx - 1] } else { 0 }
+}
+
+// CHECK-LABEL: @f2
+// CHECK-NOT: panic
+#[no_mangle]
+pub fn f2(idx: usize, buf: &[u8; 10]) -> u8 {
+    if idx > 5 && idx < 8 { buf[idx] } else { 0 }
+}
diff --git a/tests/codegen-llvm/issues/issue-75546.rs b/tests/codegen-llvm/issues/issue-75546.rs
new file mode 100644
index 00000000000..1e1e6543a88
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-75546.rs
@@ -0,0 +1,17 @@
+//@ compile-flags: -Copt-level=3
+#![crate_type = "lib"]
+
+// Test that LLVM can eliminate the impossible `i == 0` check.
+
+// CHECK-LABEL: @issue_75546
+#[no_mangle]
+pub fn issue_75546() {
+    let mut i = 1u32;
+    while i < u32::MAX {
+        // CHECK-NOT: panic
+        if i == 0 {
+            panic!();
+        }
+        i += 1;
+    }
+}
diff --git a/tests/codegen-llvm/issues/issue-75659.rs b/tests/codegen-llvm/issues/issue-75659.rs
new file mode 100644
index 00000000000..0960bfdb6b0
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-75659.rs
@@ -0,0 +1,63 @@
+// This test checks that the call to memchr/slice_contains is optimized away
+// when searching in small slices.
+
+//@ compile-flags: -Copt-level=3 -Zinline-mir=false
+//@ only-x86_64
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @foo1
+#[no_mangle]
+pub fn foo1(x: u8, data: &[u8; 1]) -> bool {
+    // CHECK-NOT: memchr
+    // CHECK-NOT: slice_contains
+    data.contains(&x)
+}
+
+// CHECK-LABEL: @foo2
+#[no_mangle]
+pub fn foo2(x: u8, data: &[u8; 2]) -> bool {
+    // CHECK-NOT: memchr
+    // CHECK-NOT: slice_contains
+    data.contains(&x)
+}
+
+// CHECK-LABEL: @foo3
+#[no_mangle]
+pub fn foo3(x: u8, data: &[u8; 3]) -> bool {
+    // CHECK-NOT: memchr
+    // CHECK-NOT: slice_contains
+    data.contains(&x)
+}
+
+// CHECK-LABEL: @foo4
+#[no_mangle]
+pub fn foo4(x: u8, data: &[u8; 4]) -> bool {
+    // CHECK-NOT: memchr
+    // CHECK-NOT: slice_contains
+    data.contains(&x)
+}
+
+// CHECK-LABEL: @foo8
+#[no_mangle]
+pub fn foo8(x: u8, data: &[u8; 8]) -> bool {
+    // CHECK-NOT: memchr
+    // CHECK-NOT: slice_contains
+    data.contains(&x)
+}
+
+// CHECK-LABEL: @foo8_i8
+#[no_mangle]
+pub fn foo8_i8(x: i8, data: &[i8; 8]) -> bool {
+    // CHECK-NOT: memchr
+    // CHECK-NOT: slice_contains
+    !data.contains(&x)
+}
+
+// Check that the general case isn't inlined
+// CHECK-LABEL: @foo80
+#[no_mangle]
+pub fn foo80(x: u8, data: &[u8; 80]) -> bool {
+    // CHECK: call core::slice::memchr
+    data.contains(&x)
+}
diff --git a/tests/codegen-llvm/issues/issue-75978.rs b/tests/codegen-llvm/issues/issue-75978.rs
new file mode 100644
index 00000000000..f4b0bc36329
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-75978.rs
@@ -0,0 +1,18 @@
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+
+#[no_mangle]
+pub fn test() -> u32 {
+    // CHECK-LABEL: @test(
+    // CHECK: ret i32 13
+    let s = [1, 2, 3, 4, 5, 6, 7];
+
+    let mut iter = s.iter();
+    let mut sum = 0;
+    while let Some(_) = iter.next() {
+        sum += iter.next().map_or(1, |&x| x)
+    }
+
+    sum
+}
diff --git a/tests/codegen-llvm/issues/issue-77812.rs b/tests/codegen-llvm/issues/issue-77812.rs
new file mode 100644
index 00000000000..09e2376c30d
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-77812.rs
@@ -0,0 +1,32 @@
+//@ compile-flags: -Copt-level=3
+#![crate_type = "lib"]
+
+// Test that LLVM can eliminate the unreachable `Variant::Zero` branch.
+
+#[derive(Copy, Clone, Eq, PartialEq)]
+pub enum Variant {
+    Zero,
+    One,
+    Two,
+}
+
+extern "C" {
+    fn exf1();
+    fn exf2();
+}
+
+pub static mut GLOBAL: Variant = Variant::Zero;
+
+// CHECK-LABEL: @issue_77812
+#[no_mangle]
+pub unsafe fn issue_77812() {
+    let g = GLOBAL;
+    if g != Variant::Zero {
+        match g {
+            Variant::One => exf1(),
+            Variant::Two => exf2(),
+            // CHECK-NOT: panic
+            Variant::Zero => panic!(),
+        }
+    }
+}
diff --git a/tests/codegen-llvm/issues/issue-84268.rs b/tests/codegen-llvm/issues/issue-84268.rs
new file mode 100644
index 00000000000..1dc55a909ad
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-84268.rs
@@ -0,0 +1,18 @@
+//@ compile-flags: -Copt-level=3 --crate-type=rlib
+#![feature(core_intrinsics, repr_simd)]
+
+use std::intrinsics::simd::{simd_eq, simd_fabs};
+
+#[repr(simd)]
+pub struct V([f32; 4]);
+
+#[repr(simd)]
+pub struct M([i32; 4]);
+
+#[no_mangle]
+// CHECK-LABEL: @is_infinite
+pub fn is_infinite(v: V) -> M {
+    // CHECK: fabs
+    // CHECK: cmp oeq
+    unsafe { simd_eq(simd_fabs(v), V([f32::INFINITY; 4])) }
+}
diff --git a/tests/codegen-llvm/issues/issue-85872-multiple-reverse.rs b/tests/codegen-llvm/issues/issue-85872-multiple-reverse.rs
new file mode 100644
index 00000000000..6f566ddee6b
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-85872-multiple-reverse.rs
@@ -0,0 +1,19 @@
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+
+#[no_mangle]
+pub fn u16_be_to_arch(mut data: [u8; 2]) -> [u8; 2] {
+    // CHECK-LABEL: @u16_be_to_arch
+    // CHECK: @llvm.bswap.i16
+    data.reverse();
+    data
+}
+
+#[no_mangle]
+pub fn u32_be_to_arch(mut data: [u8; 4]) -> [u8; 4] {
+    // CHECK-LABEL: @u32_be_to_arch
+    // CHECK: @llvm.bswap.i32
+    data.reverse();
+    data
+}
diff --git a/tests/codegen-llvm/issues/issue-86106.rs b/tests/codegen-llvm/issues/issue-86106.rs
new file mode 100644
index 00000000000..8d1ce116d26
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-86106.rs
@@ -0,0 +1,63 @@
+//@ only-64bit llvm appears to use stores instead of memset on 32bit
+//@ compile-flags: -C opt-level=3 -Z merge-functions=disabled
+//@ needs-deterministic-layouts
+
+// The below two functions ensure that both `String::new()` and `"".to_string()`
+// produce the identical code.
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: define {{(dso_local )?}}void @string_new
+#[no_mangle]
+pub fn string_new() -> String {
+    // CHECK-NOT: load i8
+    // CHECK: store i{{32|64}}
+    // CHECK-NEXT: getelementptr
+    // CHECK-NEXT: store ptr
+    // CHECK-NEXT: getelementptr
+    // CHECK-NEXT: store i{{32|64}}
+    // CHECK-NEXT: ret void
+    String::new()
+}
+
+// CHECK-LABEL: define {{(dso_local )?}}void @empty_to_string
+#[no_mangle]
+pub fn empty_to_string() -> String {
+    // CHECK-NOT: load i8
+    // CHECK: store i{{32|64}}
+    // CHECK-NEXT: getelementptr
+    // CHECK-NEXT: store ptr
+    // CHECK-NEXT: getelementptr
+    // CHECK-NEXT: store i{{32|64}}
+    // CHECK-NEXT: ret void
+    "".to_string()
+}
+
+// The below two functions ensure that both `vec![]` and `vec![].clone()`
+// produce the identical code.
+
+// CHECK-LABEL: @empty_vec
+#[no_mangle]
+pub fn empty_vec() -> Vec<u8> {
+    // CHECK: store i{{32|64}}
+    // CHECK-NOT: load i8
+    // CHECK-NEXT: getelementptr
+    // CHECK-NEXT: store ptr
+    // CHECK-NEXT: getelementptr
+    // CHECK-NEXT: store i{{32|64}}
+    // CHECK-NEXT: ret void
+    vec![]
+}
+
+// CHECK-LABEL: @empty_vec_clone
+#[no_mangle]
+pub fn empty_vec_clone() -> Vec<u8> {
+    // CHECK: store i{{32|64}}
+    // CHECK-NOT: load i8
+    // CHECK-NEXT: getelementptr
+    // CHECK-NEXT: store ptr
+    // CHECK-NEXT: getelementptr
+    // CHECK-NEXT: store i{{32|64}}
+    // CHECK-NEXT: ret void
+    vec![].clone()
+}
diff --git a/tests/codegen-llvm/issues/issue-86109-eliminate-div-by-zero-check.rs b/tests/codegen-llvm/issues/issue-86109-eliminate-div-by-zero-check.rs
new file mode 100644
index 00000000000..345c09738b6
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-86109-eliminate-div-by-zero-check.rs
@@ -0,0 +1,26 @@
+//@ compile-flags: -Copt-level=3
+//! Test for https://github.com/rust-lang/rust/issues/86109
+//! Check LLVM can eliminate the impossible division by zero check by
+//! ensuring there is no call (to panic) instruction.
+//!
+//! This has been fixed since `rustc 1.70.0`.
+
+#![crate_type = "lib"]
+
+type T = i16;
+
+// CHECK-LABEL: @foo
+#[no_mangle]
+pub fn foo(start: T) -> T {
+    // CHECK-NOT: panic
+    if start <= 0 {
+        return 0;
+    }
+    let mut count = 0;
+    for i in start..10_000 {
+        if 752 % i != 0 {
+            count += 1;
+        }
+    }
+    count
+}
diff --git a/tests/codegen-llvm/issues/issue-93036-assert-index.rs b/tests/codegen-llvm/issues/issue-93036-assert-index.rs
new file mode 100644
index 00000000000..46f45c2f06e
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-93036-assert-index.rs
@@ -0,0 +1,14 @@
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+
+#[no_mangle]
+// CHECK-LABEL: @foo
+// CHECK-NOT: unreachable
+pub fn foo(arr: &mut [u32]) {
+    for i in 0..arr.len() {
+        for j in 0..i {
+            assert!(j < arr.len());
+        }
+    }
+}
diff --git a/tests/codegen-llvm/issues/issue-96274.rs b/tests/codegen-llvm/issues/issue-96274.rs
new file mode 100644
index 00000000000..2425ec53e4e
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-96274.rs
@@ -0,0 +1,15 @@
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+
+use std::mem::MaybeUninit;
+
+pub fn maybe_uninit() -> [MaybeUninit<u8>; 3000] {
+    // CHECK-NOT: memset
+    [MaybeUninit::uninit(); 3000]
+}
+
+pub fn maybe_uninit_const<T>() -> [MaybeUninit<T>; 8192] {
+    // CHECK-NOT: memset
+    [const { MaybeUninit::uninit() }; 8192]
+}
diff --git a/tests/codegen-llvm/issues/issue-96497-slice-size-nowrap.rs b/tests/codegen-llvm/issues/issue-96497-slice-size-nowrap.rs
new file mode 100644
index 00000000000..7b3a20a295e
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-96497-slice-size-nowrap.rs
@@ -0,0 +1,38 @@
+// This test case checks that LLVM is aware that computing the size of a slice cannot wrap.
+// The possibility of wrapping results in an additional branch when dropping boxed slices
+// in some situations, see https://github.com/rust-lang/rust/issues/96497#issuecomment-1112865218
+
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @simple_size_of_nowrap
+#[no_mangle]
+pub fn simple_size_of_nowrap(x: &[u32]) -> usize {
+    // Make sure the shift used to compute the size has a nowrap flag.
+
+    // CHECK: [[A:%.*]] = shl nuw nsw {{.*}}, 2
+    // CHECK-NEXT: ret {{.*}} [[A]]
+    core::mem::size_of_val(x)
+}
+
+// CHECK-LABEL: @drop_write
+#[no_mangle]
+pub fn drop_write(mut x: Box<[u32]>) {
+    // Check that this write is optimized out.
+    // This depends on the size calculation not wrapping,
+    // since otherwise LLVM can't tell that the memory is always deallocated if the slice len > 0.
+
+    // CHECK-NOT: store i32 42
+    x[1] = 42;
+}
+
+// CHECK-LABEL: @slice_size_plus_2
+#[no_mangle]
+pub fn slice_size_plus_2(x: &[u16]) -> usize {
+    // Before #136575 this didn't get the `nuw` in the add.
+
+    // CHECK: [[BYTES:%.+]] = shl nuw nsw {{i16|i32|i64}} %x.1, 1
+    // CHECK: = add nuw {{i16|i32|i64}} [[BYTES]], 2
+    core::mem::size_of_val(x) + 2
+}
diff --git a/tests/codegen-llvm/issues/issue-98294-get-mut-copy-from-slice-opt.rs b/tests/codegen-llvm/issues/issue-98294-get-mut-copy-from-slice-opt.rs
new file mode 100644
index 00000000000..76adcf9fd45
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-98294-get-mut-copy-from-slice-opt.rs
@@ -0,0 +1,17 @@
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+
+// There should be no calls to panic / len_mismatch_fail.
+
+#[no_mangle]
+pub fn test(a: &mut [u8], offset: usize, bytes: &[u8]) {
+    // CHECK-LABEL: @test(
+    // CHECK-NOT: call
+    // CHECK: call void @llvm.memcpy
+    // CHECK-NOT: call
+    // CHECK: }
+    if let Some(dst) = a.get_mut(offset..offset + bytes.len()) {
+        dst.copy_from_slice(bytes);
+    }
+}
diff --git a/tests/codegen-llvm/issues/issue-98678-async.rs b/tests/codegen-llvm/issues/issue-98678-async.rs
new file mode 100644
index 00000000000..3dd06bb5194
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-98678-async.rs
@@ -0,0 +1,27 @@
+// ignore-tidy-linelength
+//! This test verifies the accuracy of emitted file and line debuginfo metadata for async blocks and
+//! async functions.
+
+//@ revisions: MSVC NONMSVC
+//@[MSVC] only-msvc
+//@[NONMSVC] ignore-msvc
+//@ edition:2021
+//@ compile-flags: --crate-type=lib -Copt-level=0 -Cdebuginfo=2 -Zdebug-info-type-line-numbers=true
+
+// NONMSVC-DAG: ![[#FILE:]] = !DIFile({{.*}}filename:{{.*[/\\]}}issue-98678-async.rs{{".*}})
+// MSVC: ![[#FILE:]] = !DIFile({{.*}}filename:{{.*}}\\issue-98678-async.rs{{".*}})
+
+// NONMSVC-DAG: !DISubprogram(name: "foo",{{.*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 2]],
+// MSVC-DAG: !DISubprogram(name: "foo",{{.*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]],
+pub async fn foo() -> u8 {
+    5
+}
+
+pub fn bar() -> impl std::future::Future<Output = u8> {
+    // NONMSVC: !DICompositeType({{.*"}}{async_block_env#0}{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 2]],
+    // MSVC-DAG: !DICompositeType({{.*"}}enum2$<issue_98678_async::bar::async_block_env$0>{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]],
+    async {
+        let x: u8 = foo().await;
+        x + 5
+    }
+}
diff --git a/tests/codegen-llvm/issues/issue-98678-closure-coroutine.rs b/tests/codegen-llvm/issues/issue-98678-closure-coroutine.rs
new file mode 100644
index 00000000000..8763bcb799d
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-98678-closure-coroutine.rs
@@ -0,0 +1,25 @@
+// ignore-tidy-linelength
+//! This test verifies the accuracy of emitted file and line debuginfo metadata for closures and
+//! coroutines.
+
+#![feature(coroutines, stmt_expr_attributes)]
+
+//@ revisions: MSVC NONMSVC
+//@[MSVC] only-msvc
+//@[NONMSVC] ignore-msvc
+//@ compile-flags: --crate-type=lib -Copt-level=0 -Cdebuginfo=2 -Zdebug-info-type-line-numbers=true
+
+// NONMSVC-DAG: ![[#FILE:]] = !DIFile({{.*}}filename:{{.*[/\\]}}issue-98678-closure-coroutine.rs{{".*}})
+// MSVC-DAG: ![[#FILE:]] = !DIFile({{.*}}filename:{{.*}}\\issue-98678-closure-coroutine.rs{{".*}})
+
+pub fn foo() {
+    // NONMSVC-DAG: !DICompositeType({{.*"}}{closure_env#0}{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 2]],
+    // MSVC-DAG: !DICompositeType({{.*"}}closure_env$0{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]],
+    let closure = |x| x;
+    closure(0);
+
+    // NONMSVC-DAG: !DICompositeType({{.*"[{]}}coroutine_env#1{{[}]".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 3]],
+    // MSVC-DAG: !DICompositeType({{.*".*foo::}}coroutine_env$1>{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 2]],
+    let _coroutine = #[coroutine]
+    || yield 1;
+}
diff --git a/tests/codegen-llvm/issues/issue-98678-enum.rs b/tests/codegen-llvm/issues/issue-98678-enum.rs
new file mode 100644
index 00000000000..87bf8797293
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-98678-enum.rs
@@ -0,0 +1,42 @@
+// ignore-tidy-linelength
+//! This test verifies the accuracy of emitted file and line debuginfo metadata enums.
+
+//@ revisions: MSVC NONMSVC
+//@[MSVC] only-msvc
+//@[NONMSVC] ignore-msvc
+//@ compile-flags: --crate-type=lib -Copt-level=0 -Cdebuginfo=2 -Zdebug-info-type-line-numbers=true
+
+// NONMSVC: ![[#FILE:]] = !DIFile({{.*}}filename:{{.*[/\\]}}issue-98678-enum.rs{{".*}})
+// MSVC: ![[#FILE:]] = !DIFile({{.*}}filename:{{.*}}\\issue-98678-enum.rs{{".*}})
+
+// NONMSVC: !DICompositeType({{.*"}}SingleCase{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 2]],
+// MSVC: !DICompositeType({{.*"}}enum2$<issue_98678_enum::SingleCase>{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]],
+pub enum SingleCase {
+    // NONMSVC: !DIDerivedType(tag: DW_TAG_member, name: "One",{{.*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 2]],
+    // CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "One",{{.*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]],
+    One,
+}
+
+// NONMSVC: !DICompositeType({{.*"}}MultipleDataCases{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 2]],
+// MSVC: !DICompositeType({{.*"}}enum2$<issue_98678_enum::MultipleDataCases>{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]],
+pub enum MultipleDataCases {
+    // NONMSVC: !DIDerivedType(tag: DW_TAG_member, name: "Case1",{{.*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 2]],
+    // CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "Case1",{{.*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]],
+    Case1(u32),
+    // NONMSVC: !DIDerivedType(tag: DW_TAG_member, name: "Case2",{{.*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 2]],
+    // CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "Case2",{{.*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]],
+    Case2(i64),
+}
+
+// NONMSVC: !DICompositeType({{.*"}}NicheLayout{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 2]],
+// MSVC: !DICompositeType({{.*"}}enum2$<issue_98678_enum::NicheLayout>{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]],
+pub enum NicheLayout {
+    // NONMSVC: !DIDerivedType(tag: DW_TAG_member, name: "Something",{{.*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 2]],
+    // CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "Something",{{.*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]],
+    Something(&'static u32),
+    // NONMSVC: !DIDerivedType(tag: DW_TAG_member, name: "Nothing",{{.*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 2]],
+    // CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "Nothing",{{.*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]],
+    Nothing,
+}
+
+pub fn foo(_: SingleCase, _: MultipleDataCases, _: NicheLayout) {}
diff --git a/tests/codegen-llvm/issues/issue-98678-struct-union.rs b/tests/codegen-llvm/issues/issue-98678-struct-union.rs
new file mode 100644
index 00000000000..a83a585a433
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-98678-struct-union.rs
@@ -0,0 +1,27 @@
+// ignore-tidy-linelength
+//! This test verifies the accuracy of emitted file and line debuginfo metadata for structs and
+//! unions.
+
+//@ revisions: MSVC NONMSVC
+//@[MSVC] only-msvc
+//@[NONMSVC] ignore-msvc
+//@ compile-flags: --crate-type=lib -Copt-level=0 -Cdebuginfo=2 -Zdebug-info-type-line-numbers=true
+
+// NONMSVC: ![[#FILE:]] = !DIFile({{.*}}filename:{{.*[/\\]}}issue-98678-struct-union.rs{{".*}})
+// MSVC: ![[#FILE:]] = !DIFile({{.*}}filename:{{.*}}\\issue-98678-struct-union.rs{{".*}})
+
+// CHECK: !DICompositeType({{.*"}}MyType{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]],
+pub struct MyType {
+    // CHECK: !DIDerivedType({{.*"}}i{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]],
+    i: i32,
+}
+
+// CHECK: !DICompositeType({{.*"}}MyUnion{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]],
+pub union MyUnion {
+    // CHECK: !DIDerivedType({{.*"}}i{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]],
+    i: i32,
+    // CHECK: !DIDerivedType({{.*"}}f{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]],
+    f: f32,
+}
+
+pub fn foo(_: MyType, _: MyUnion) {}
diff --git a/tests/codegen-llvm/issues/issue-99960.rs b/tests/codegen-llvm/issues/issue-99960.rs
new file mode 100644
index 00000000000..571a9be967d
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-99960.rs
@@ -0,0 +1,10 @@
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+
+#[no_mangle]
+pub fn test(dividend: i64, divisor: i64) -> Option<i64> {
+    // CHECK-LABEL: @test(
+    // CHECK-NOT: panic
+    if dividend > i64::min_value() && divisor != 0 { Some(dividend / divisor) } else { None }
+}
diff --git a/tests/codegen-llvm/issues/looping-over-ne-bytes-133528.rs b/tests/codegen-llvm/issues/looping-over-ne-bytes-133528.rs
new file mode 100644
index 00000000000..35acf765d69
--- /dev/null
+++ b/tests/codegen-llvm/issues/looping-over-ne-bytes-133528.rs
@@ -0,0 +1,17 @@
+//@ compile-flags: -Copt-level=3
+//@ min-llvm-version: 20
+#![crate_type = "lib"]
+
+/// Ensure the function is properly optimized
+/// In the issue #133528, the function was not getting optimized
+/// whereas, a version with `bytes` wrapped into a `black_box` was optimized
+/// It was probably a LLVM bug that was fixed in LLVM 20
+
+// CHECK-LABEL: @looping_over_ne_bytes
+// CHECK: icmp eq i64 %input, -1
+// CHECK-NEXT: ret i1
+#[no_mangle]
+fn looping_over_ne_bytes(input: u64) -> bool {
+    let bytes = input.to_ne_bytes();
+    bytes.iter().all(|x| *x == !0)
+}
diff --git a/tests/codegen-llvm/issues/str-to-string-128690.rs b/tests/codegen-llvm/issues/str-to-string-128690.rs
new file mode 100644
index 00000000000..d9e69764be2
--- /dev/null
+++ b/tests/codegen-llvm/issues/str-to-string-128690.rs
@@ -0,0 +1,38 @@
+//@ compile-flags: -C opt-level=3 -Z merge-functions=disabled
+#![crate_type = "lib"]
+
+//! Make sure str::to_string is specialized not to use fmt machinery.
+//!
+//! Note that the `CHECK-NOT`s here try to match on calls to functions under `core::fmt`.
+
+// CHECK-LABEL: define {{(dso_local )?}}void @one_ref
+#[no_mangle]
+pub fn one_ref(input: &str) -> String {
+    // CHECK-NOT: {{(call|invoke)}}{{.*}}@{{.*}}core{{.*}}fmt{{.*}}
+    input.to_string()
+}
+
+// CHECK-LABEL: define {{(dso_local )?}}void @two_ref
+#[no_mangle]
+pub fn two_ref(input: &&str) -> String {
+    // CHECK-NOT: {{(call|invoke)}}{{.*}}@{{.*}}core{{.*}}fmt{{.*}}
+    input.to_string()
+}
+
+// CHECK-LABEL: define {{(dso_local )?}}void @thirteen_ref
+#[no_mangle]
+pub fn thirteen_ref(input: &&&&&&&&&&&&&str) -> String {
+    // CHECK-NOT: {{(call|invoke)}}{{.*}}@{{.*}}core{{.*}}fmt{{.*}}
+    input.to_string()
+}
+
+// This is a known performance cliff because of the macro-generated
+// specialized impl. If this test suddenly starts failing,
+// consider removing the `to_string_str!` macro in `alloc/str/string.rs`.
+//
+// CHECK-LABEL: define {{(dso_local )?}}void @fourteen_ref
+#[no_mangle]
+pub fn fourteen_ref(input: &&&&&&&&&&&&&&str) -> String {
+    // CHECK: {{(call|invoke)}}{{.*}}@{{.*}}core{{.*}}fmt{{.*}}
+    input.to_string()
+}
diff --git a/tests/codegen-llvm/iter-repeat-n-trivial-drop.rs b/tests/codegen-llvm/iter-repeat-n-trivial-drop.rs
new file mode 100644
index 00000000000..28173530324
--- /dev/null
+++ b/tests/codegen-llvm/iter-repeat-n-trivial-drop.rs
@@ -0,0 +1,70 @@
+//@ compile-flags: -C opt-level=3
+//@ only-x86_64
+//@ needs-deterministic-layouts
+
+#![crate_type = "lib"]
+#![feature(iter_repeat_n)]
+#![feature(array_repeat)]
+
+#[derive(Clone)]
+pub struct NotCopy(u16);
+
+impl Drop for NotCopy {
+    fn drop(&mut self) {}
+}
+
+// For a type where `Drop::drop` doesn't do anything observable and a clone is the
+// same as a move, make sure that the extra case for the last item disappears.
+
+#[no_mangle]
+// CHECK-LABEL: @iter_repeat_n_next
+pub fn iter_repeat_n_next(it: &mut std::iter::RepeatN<NotCopy>) -> Option<NotCopy> {
+    // CHECK-NEXT: start:
+    // CHECK-NOT: br
+    // CHECK: %[[COUNT:.+]] = load i64
+    // CHECK-NEXT: %[[COUNT_ZERO:.+]] = icmp eq i64 %[[COUNT]], 0
+    // CHECK-NEXT: br i1 %[[COUNT_ZERO]], label %[[EMPTY:.+]], label %[[NOT_EMPTY:.+]]
+
+    // CHECK: [[NOT_EMPTY]]:
+    // CHECK-NOT: br
+    // CHECK: %[[DEC:.+]] = add i64 %[[COUNT]], -1
+    // CHECK-NEXT: %[[VAL:.+]] = load i16
+    // CHECK-NEXT: store i64 %[[DEC]]
+    // CHECK-NEXT: br label %[[EMPTY]]
+
+    // CHECK: [[EMPTY]]:
+    // CHECK-NOT: br
+    // CHECK: phi i16
+    // CHECK-SAME: [ %[[VAL]], %[[NOT_EMPTY]] ]
+    // CHECK-NOT: br
+    // CHECK: ret
+
+    it.next()
+}
+
+// And as a result, using the iterator can optimize without special cases for
+// the last iteration, like `memset`ing all the items in one call.
+
+#[no_mangle]
+// CHECK-LABEL: @vec_extend_via_iter_repeat_n
+pub fn vec_extend_via_iter_repeat_n() -> Vec<u8> {
+    // CHECK: %[[ADDR:.+]] = tail call {{(noalias )?}}noundef dereferenceable_or_null(1234) ptr @{{.*}}__rust_alloc(i64 noundef {{(range\(i64 1, 0\) )?}}1234, i64 noundef {{(range\(i64 1, -9223372036854775807\) )?}}1)
+    // CHECK: tail call void @llvm.memset.p0.i64(ptr noundef nonnull align 1 dereferenceable(1234) %[[ADDR]], i8 42, i64 1234,
+
+    let n = 1234_usize;
+    let mut v = Vec::with_capacity(n);
+    v.extend(std::iter::repeat_n(42_u8, n));
+    v
+}
+
+// Array repeat uses `RepeatN::next_unchecked` internally,
+// so also check that the distinction disappears there.
+
+#[no_mangle]
+// CHECK-LABEL: @array_repeat_not_copy
+pub unsafe fn array_repeat_not_copy(item: NotCopy) -> [NotCopy; 8] {
+    // CHECK: insertelement {{.+}} i16 %item
+    // CHECK: shufflevector <8 x i16> {{.+}} zeroinitializer
+    // CHECK: store <8 x i16>
+    std::array::repeat(item)
+}
diff --git a/tests/codegen-llvm/layout-size-checks.rs b/tests/codegen-llvm/layout-size-checks.rs
new file mode 100644
index 00000000000..d64a7055e0b
--- /dev/null
+++ b/tests/codegen-llvm/layout-size-checks.rs
@@ -0,0 +1,30 @@
+//@ compile-flags: -Copt-level=3
+//@ only-x86_64
+
+#![crate_type = "lib"]
+
+use std::alloc::Layout;
+
+type RGB48 = [u16; 3];
+
+// CHECK-LABEL: @layout_array_rgb48
+#[no_mangle]
+pub fn layout_array_rgb48(n: usize) -> Layout {
+    // CHECK-NOT: llvm.umul.with.overflow.i64
+    // CHECK: icmp ugt i64 %n, 1537228672809129301
+    // CHECK-NOT: llvm.umul.with.overflow.i64
+    // CHECK: mul nuw nsw i64 %n, 6
+    // CHECK-NOT: llvm.umul.with.overflow.i64
+    Layout::array::<RGB48>(n).unwrap()
+}
+
+// CHECK-LABEL: @layout_array_i32
+#[no_mangle]
+pub fn layout_array_i32(n: usize) -> Layout {
+    // CHECK-NOT: llvm.umul.with.overflow.i64
+    // CHECK: icmp ugt i64 %n, 2305843009213693951
+    // CHECK-NOT: llvm.umul.with.overflow.i64
+    // CHECK: shl nuw nsw i64 %n, 2
+    // CHECK-NOT: llvm.umul.with.overflow.i64
+    Layout::array::<i32>(n).unwrap()
+}
diff --git a/tests/codegen-llvm/lib-optimizations/iter-sum.rs b/tests/codegen-llvm/lib-optimizations/iter-sum.rs
new file mode 100644
index 00000000000..a054ffffe74
--- /dev/null
+++ b/tests/codegen-llvm/lib-optimizations/iter-sum.rs
@@ -0,0 +1,13 @@
+//@ compile-flags: -Copt-level=3
+//@ only-x86_64 (vectorization varies between architectures)
+#![crate_type = "lib"]
+
+// Ensure that slice + take + sum gets vectorized.
+// Currently this relies on the slice::Iter::try_fold implementation
+// CHECK-LABEL: @slice_take_sum
+#[no_mangle]
+pub fn slice_take_sum(s: &[u64], l: usize) -> u64 {
+    // CHECK: vector.body:
+    // CHECK: ret
+    s.iter().take(l).sum()
+}
diff --git a/tests/codegen-llvm/lib-optimizations/slice_rotate.rs b/tests/codegen-llvm/lib-optimizations/slice_rotate.rs
new file mode 100644
index 00000000000..aa4bb3b528c
--- /dev/null
+++ b/tests/codegen-llvm/lib-optimizations/slice_rotate.rs
@@ -0,0 +1,30 @@
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+
+// Ensure that the simple case of rotating by a constant 1 optimizes to the obvious thing
+
+// CHECK-LABEL: @rotate_left_by_one
+#[no_mangle]
+pub fn rotate_left_by_one(slice: &mut [i32]) {
+    // CHECK-NOT: phi
+    // CHECK-NOT: call
+    // CHECK-NOT: load
+    // CHECK-NOT: store
+    // CHECK-NOT: getelementptr
+    // CHECK: %[[END:.+]] = getelementptr
+    // CHECK-NEXT: %[[DIM:.+]] = getelementptr
+    // CHECK-NEXT: %[[LAST:.+]] = load
+    // CHECK-NEXT: %[[FIRST:.+]] = shl
+    // CHECK-NEXT: call void @llvm.memmove
+    // CHECK-NEXT: store i32 %[[LAST]], ptr %[[DIM:.+]]
+    // CHECK-NOT: phi
+    // CHECK-NOT: call
+    // CHECK-NOT: load
+    // CHECK-NOT: store
+    // CHECK-NOT: getelementptr
+    // CHECK: ret void
+    if !slice.is_empty() {
+        slice.rotate_left(1);
+    }
+}
diff --git a/tests/codegen-llvm/lifetime_start_end.rs b/tests/codegen-llvm/lifetime_start_end.rs
new file mode 100644
index 00000000000..0639e7640aa
--- /dev/null
+++ b/tests/codegen-llvm/lifetime_start_end.rs
@@ -0,0 +1,34 @@
+//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes -Zmir-opt-level=0
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @test
+#[no_mangle]
+pub fn test() {
+    let a = 0u8;
+    &a; // keep variable in an alloca
+
+    // CHECK: call void @llvm.lifetime.start{{.*}}(i{{[0-9 ]+}}, ptr %a)
+
+    {
+        let b = &Some(a);
+        &b; // keep variable in an alloca
+
+        // CHECK: call void @llvm.lifetime.start{{.*}}(i{{[0-9 ]+}}, {{.*}})
+
+        // CHECK: call void @llvm.lifetime.start{{.*}}(i{{[0-9 ]+}}, {{.*}})
+
+        // CHECK: call void @llvm.lifetime.end{{.*}}(i{{[0-9 ]+}}, {{.*}})
+
+        // CHECK: call void @llvm.lifetime.end{{.*}}(i{{[0-9 ]+}}, {{.*}})
+    }
+
+    let c = 1u8;
+    &c; // keep variable in an alloca
+
+    // CHECK: call void @llvm.lifetime.start{{.*}}(i{{[0-9 ]+}}, ptr %c)
+
+    // CHECK: call void @llvm.lifetime.end{{.*}}(i{{[0-9 ]+}}, ptr %c)
+
+    // CHECK: call void @llvm.lifetime.end{{.*}}(i{{[0-9 ]+}}, ptr %a)
+}
diff --git a/tests/codegen-llvm/link-dead-code.rs b/tests/codegen-llvm/link-dead-code.rs
new file mode 100644
index 00000000000..93e1d84d9c7
--- /dev/null
+++ b/tests/codegen-llvm/link-dead-code.rs
@@ -0,0 +1,28 @@
+//@ compile-flags:-Clink-dead-code
+
+#![crate_type = "rlib"]
+
+// This test makes sure that, when -Clink-dead-code is specified, we generate
+// code for functions that would otherwise be skipped.
+
+// CHECK-LABEL: ; link_dead_code::const_fn
+// CHECK-NEXT: ; Function Attrs:
+// CHECK-NEXT: define hidden
+const fn const_fn() -> i32 {
+    1
+}
+
+// CHECK-LABEL: ; link_dead_code::inline_fn
+// CHECK-NEXT: ; Function Attrs:
+// CHECK-NEXT: define hidden
+#[inline]
+fn inline_fn() -> i32 {
+    2
+}
+
+// CHECK-LABEL: ; link_dead_code::private_fn
+// CHECK-NEXT: ; Function Attrs:
+// CHECK-NEXT: define hidden
+fn private_fn() -> i32 {
+    3
+}
diff --git a/tests/codegen-llvm/link_section.rs b/tests/codegen-llvm/link_section.rs
new file mode 100644
index 00000000000..f62f6948079
--- /dev/null
+++ b/tests/codegen-llvm/link_section.rs
@@ -0,0 +1,35 @@
+//@ ignore-wasm32 custom sections work differently on wasm
+//@ compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+// CHECK: @VAR1 = {{(dso_local )?}}constant [4 x i8] c"\01\00\00\00", section ".test_one"
+#[no_mangle]
+#[link_section = ".test_one"]
+#[cfg(target_endian = "little")]
+pub static VAR1: u32 = 1;
+
+#[no_mangle]
+#[link_section = ".test_one"]
+#[cfg(target_endian = "big")]
+pub static VAR1: u32 = 0x01000000;
+
+pub enum E {
+    A(u32),
+    B(f32),
+}
+
+// CHECK: @VAR2 = {{(dso_local )?}}constant {{.*}}, section ".test_two"
+#[no_mangle]
+#[link_section = ".test_two"]
+pub static VAR2: E = E::A(666);
+
+// CHECK: @VAR3 = {{(dso_local )?}}constant {{.*}}, section ".test_three"
+#[no_mangle]
+#[link_section = ".test_three"]
+pub static VAR3: E = E::B(1.);
+
+// CHECK: define {{(dso_local )?}}void @fn1() {{.*}} section ".test_four" {
+#[no_mangle]
+#[link_section = ".test_four"]
+pub fn fn1() {}
diff --git a/tests/codegen-llvm/llvm-ident.rs b/tests/codegen-llvm/llvm-ident.rs
new file mode 100644
index 00000000000..923e99bb282
--- /dev/null
+++ b/tests/codegen-llvm/llvm-ident.rs
@@ -0,0 +1,15 @@
+// Verifies that the `!llvm.ident` named metadata is emitted.
+//
+//@ revisions: NONE OPT DEBUG
+//
+//@ [OPT] compile-flags: -Copt-level=2
+//@ [DEBUG] compile-flags: -Cdebuginfo=2
+
+// The named metadata should contain a single metadata node (see
+// `LLVMRustPrepareThinLTOImport` for details).
+// CHECK: !llvm.ident = !{![[ID:[0-9]+]]}
+
+// In addition, check that the metadata node has the expected content.
+// CHECK: ![[ID]] = !{!"rustc version 1.{{.*}}"}
+
+fn main() {}
diff --git a/tests/codegen-llvm/llvm_module_flags.rs b/tests/codegen-llvm/llvm_module_flags.rs
new file mode 100644
index 00000000000..d3fae0c3927
--- /dev/null
+++ b/tests/codegen-llvm/llvm_module_flags.rs
@@ -0,0 +1,7 @@
+// Test for -Z llvm_module_flags
+//@ compile-flags: -Z llvm_module_flag=foo:u32:123:error -Z llvm_module_flag=bar:u32:42:max
+
+fn main() {}
+
+// CHECK: !{i32 1, !"foo", i32 123}
+// CHECK: !{i32 7, !"bar", i32 42}
diff --git a/tests/codegen-llvm/loads.rs b/tests/codegen-llvm/loads.rs
new file mode 100644
index 00000000000..88d67642b72
--- /dev/null
+++ b/tests/codegen-llvm/loads.rs
@@ -0,0 +1,152 @@
+//@ compile-flags: -C no-prepopulate-passes -Zmir-opt-level=0 -Copt-level=3
+
+#![crate_type = "lib"]
+
+use std::mem::MaybeUninit;
+use std::num::NonZero;
+
+pub struct Bytes {
+    a: u8,
+    b: u8,
+    c: u8,
+    d: u8,
+}
+
+#[derive(Copy, Clone)]
+pub enum MyBool {
+    True,
+    False,
+}
+
+#[repr(align(16))]
+pub struct Align16(u128);
+
+// CHECK: @ptr_alignment_helper({{.*}}align [[PTR_ALIGNMENT:[0-9]+]]
+#[no_mangle]
+pub fn ptr_alignment_helper(x: &&()) {}
+
+// CHECK-LABEL: @load_ref
+#[no_mangle]
+pub fn load_ref<'a>(x: &&'a i32) -> &'a i32 {
+    // CHECK: load ptr, ptr %x, align [[PTR_ALIGNMENT]], !nonnull !{{[0-9]+}}, !align ![[ALIGN_4_META:[0-9]+]], !noundef !{{[0-9]+}}
+    *x
+}
+
+// CHECK-LABEL: @load_ref_higher_alignment
+#[no_mangle]
+pub fn load_ref_higher_alignment<'a>(x: &&'a Align16) -> &'a Align16 {
+    // CHECK: load ptr, ptr %x, align [[PTR_ALIGNMENT]], !nonnull !{{[0-9]+}}, !align ![[ALIGN_16_META:[0-9]+]], !noundef !{{[0-9]+}}
+    *x
+}
+
+// CHECK-LABEL: @load_scalar_pair
+#[no_mangle]
+pub fn load_scalar_pair<'a>(x: &(&'a i32, &'a Align16)) -> (&'a i32, &'a Align16) {
+    // CHECK: load ptr, ptr %{{.+}}, align [[PTR_ALIGNMENT]], !nonnull !{{[0-9]+}}, !align ![[ALIGN_4_META]], !noundef !{{[0-9]+}}
+    // CHECK: load ptr, ptr %{{.+}}, align [[PTR_ALIGNMENT]], !nonnull !{{[0-9]+}}, !align ![[ALIGN_16_META]], !noundef !{{[0-9]+}}
+    *x
+}
+
+// CHECK-LABEL: @load_raw_pointer
+#[no_mangle]
+pub fn load_raw_pointer<'a>(x: &*const i32) -> *const i32 {
+    // loaded raw pointer should not have !nonnull or !align metadata
+    // CHECK: load ptr, ptr %x, align [[PTR_ALIGNMENT]], !noundef ![[NOUNDEF:[0-9]+]]{{$}}
+    *x
+}
+
+// CHECK-LABEL: @load_box
+#[no_mangle]
+pub fn load_box<'a>(x: Box<Box<i32>>) -> Box<i32> {
+    // CHECK: load ptr, ptr %{{.*}}, align [[PTR_ALIGNMENT]], !nonnull !{{[0-9]+}}, !align ![[ALIGN_4_META]], !noundef !{{[0-9]+}}
+    *x
+}
+
+// CHECK-LABEL: @load_bool
+#[no_mangle]
+pub fn load_bool(x: &bool) -> bool {
+    // CHECK: load i8, ptr %x, align 1, !range ![[BOOL_RANGE:[0-9]+]], !noundef !{{[0-9]+}}
+    *x
+}
+
+// CHECK-LABEL: @load_maybeuninit_bool
+#[no_mangle]
+pub fn load_maybeuninit_bool(x: &MaybeUninit<bool>) -> MaybeUninit<bool> {
+    // CHECK: load i8, ptr %x, align 1{{$}}
+    *x
+}
+
+// CHECK-LABEL: @load_enum_bool
+#[no_mangle]
+pub fn load_enum_bool(x: &MyBool) -> MyBool {
+    // CHECK: load i8, ptr %x, align 1, !range ![[BOOL_RANGE]], !noundef !{{[0-9]+}}
+    *x
+}
+
+// CHECK-LABEL: @load_maybeuninit_enum_bool
+#[no_mangle]
+pub fn load_maybeuninit_enum_bool(x: &MaybeUninit<MyBool>) -> MaybeUninit<MyBool> {
+    // CHECK: load i8, ptr %x, align 1{{$}}
+    *x
+}
+
+// CHECK-LABEL: @load_int
+#[no_mangle]
+pub fn load_int(x: &u16) -> u16 {
+    // CHECK: load i16, ptr %x, align 2, !noundef ![[NOUNDEF]]{{$}}
+    *x
+}
+
+// CHECK-LABEL: @load_nonzero_int
+#[no_mangle]
+pub fn load_nonzero_int(x: &NonZero<u16>) -> NonZero<u16> {
+    // CHECK: load i16, ptr %x, align 2, !range ![[NONZEROU16_RANGE:[0-9]+]], !noundef !{{[0-9]+}}
+    *x
+}
+
+// CHECK-LABEL: @load_option_nonzero_int
+#[no_mangle]
+pub fn load_option_nonzero_int(x: &Option<NonZero<u16>>) -> Option<NonZero<u16>> {
+    // CHECK: load i16, ptr %x, align 2, !noundef ![[NOUNDEF]]{{$}}
+    *x
+}
+
+// CHECK-LABEL: @borrow
+#[no_mangle]
+pub fn borrow(x: &i32) -> &i32 {
+    // CHECK: load ptr, ptr %x{{.*}}, !nonnull
+    &x; // keep variable in an alloca
+    x
+}
+
+// CHECK-LABEL: @_box
+#[no_mangle]
+pub fn _box(x: Box<i32>) -> i32 {
+    // CHECK: load ptr, ptr %x{{.*}}, align [[PTR_ALIGNMENT]]
+    *x
+}
+
+// CHECK-LABEL: small_array_alignment
+// The array is loaded as i32, but its alignment is lower, go with 1 byte to avoid target
+// dependent alignment
+#[no_mangle]
+pub fn small_array_alignment(x: [i8; 4]) -> [i8; 4] {
+    // CHECK: [[VAR:%[0-9]+]] = load i32, ptr %{{.*}}, align 1
+    // CHECK: ret i32 [[VAR]]
+    x
+}
+
+// CHECK-LABEL: small_struct_alignment
+// The struct is loaded as i32, but its alignment is lower, go with 1 byte to avoid target
+// dependent alignment
+#[no_mangle]
+pub fn small_struct_alignment(x: Bytes) -> Bytes {
+    // CHECK: [[VAR:%[0-9]+]] = load i32, ptr %{{.*}}, align 1
+    // CHECK: ret i32 [[VAR]]
+    x
+}
+
+// CHECK-DAG: ![[BOOL_RANGE]] = !{i8 0, i8 2}
+// CHECK-DAG: ![[NONZEROU16_RANGE]] = !{i16 1, i16 0}
+// CHECK-DAG: ![[ALIGN_4_META]] = !{i64 4}
+// CHECK-DAG: ![[ALIGN_16_META]] = !{i64 16}
diff --git a/tests/codegen-llvm/local-generics-in-exe-internalized.rs b/tests/codegen-llvm/local-generics-in-exe-internalized.rs
new file mode 100644
index 00000000000..8dbc41382b5
--- /dev/null
+++ b/tests/codegen-llvm/local-generics-in-exe-internalized.rs
@@ -0,0 +1,14 @@
+//@ compile-flags: -C no-prepopulate-passes -Zshare-generics=yes -Zinline-mir=no
+
+// Check that local generics are internalized if they are in the same CGU
+
+// CHECK-LABEL: ; local_generics_in_exe_internalized::foo
+// CHECK-NEXT: ; Function Attrs:
+// CHECK-NEXT: define internal
+pub fn foo<T>(x: T, y: T) -> (T, T) {
+    (x, y)
+}
+
+fn main() {
+    let _ = foo(0u8, 1u8);
+}
diff --git a/tests/codegen-llvm/loongarch-abi/call-llvm-intrinsics.rs b/tests/codegen-llvm/loongarch-abi/call-llvm-intrinsics.rs
new file mode 100644
index 00000000000..9a50f7b8e3a
--- /dev/null
+++ b/tests/codegen-llvm/loongarch-abi/call-llvm-intrinsics.rs
@@ -0,0 +1,31 @@
+//@ compile-flags: -C no-prepopulate-passes
+
+//@ only-loongarch64
+
+#![feature(link_llvm_intrinsics)]
+#![crate_type = "lib"]
+
+struct A;
+
+impl Drop for A {
+    fn drop(&mut self) {
+        println!("A");
+    }
+}
+
+extern "C" {
+    #[link_name = "llvm.sqrt.f32"]
+    fn sqrt(x: f32) -> f32;
+}
+
+pub fn do_call() {
+    let _a = A;
+
+    unsafe {
+        // Ensure that we `call` LLVM intrinsics instead of trying to `invoke` them
+        // CHECK: store float 4.000000e+00, ptr %{{.}}, align 4
+        // CHECK: load float, ptr %{{.}}, align 4
+        // CHECK: call float @llvm.sqrt.f32(float %{{.}}
+        sqrt(4.0);
+    }
+}
diff --git a/tests/codegen-llvm/loongarch-abi/loongarch64-lp64d-abi.rs b/tests/codegen-llvm/loongarch-abi/loongarch64-lp64d-abi.rs
new file mode 100644
index 00000000000..93c8d60930b
--- /dev/null
+++ b/tests/codegen-llvm/loongarch-abi/loongarch64-lp64d-abi.rs
@@ -0,0 +1,299 @@
+//@ add-core-stubs
+//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes --target loongarch64-unknown-linux-gnu
+//@ needs-llvm-components: loongarch
+
+#![feature(no_core, lang_items)]
+#![crate_type = "lib"]
+#![no_std]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+// CHECK: define void @f_fpr_tracking(double %0, double %1, double %2, double %3, double %4, double %5, double %6, double %7, i8 noundef zeroext %i)
+#[no_mangle]
+pub extern "C" fn f_fpr_tracking(
+    a: f64,
+    b: f64,
+    c: f64,
+    d: f64,
+    e: f64,
+    f: f64,
+    g: f64,
+    h: f64,
+    i: u8,
+) {
+}
+
+#[repr(C)]
+pub struct Double {
+    f: f64,
+}
+
+#[repr(C)]
+pub struct DoubleDouble {
+    f: f64,
+    g: f64,
+}
+
+#[repr(C)]
+pub struct DoubleFloat {
+    f: f64,
+    g: f32,
+}
+
+// CHECK: define void @f_double_s_arg(double %0)
+#[no_mangle]
+pub extern "C" fn f_double_s_arg(a: Double) {}
+
+// CHECK: define double @f_ret_double_s()
+#[no_mangle]
+pub extern "C" fn f_ret_double_s() -> Double {
+    Double { f: 1. }
+}
+
+// CHECK: define void @f_double_double_s_arg({ double, double } %0)
+#[no_mangle]
+pub extern "C" fn f_double_double_s_arg(a: DoubleDouble) {}
+
+// CHECK: define { double, double } @f_ret_double_double_s()
+#[no_mangle]
+pub extern "C" fn f_ret_double_double_s() -> DoubleDouble {
+    DoubleDouble { f: 1., g: 2. }
+}
+
+// CHECK: define void @f_double_float_s_arg({ double, float } %0)
+#[no_mangle]
+pub extern "C" fn f_double_float_s_arg(a: DoubleFloat) {}
+
+// CHECK: define { double, float } @f_ret_double_float_s()
+#[no_mangle]
+pub extern "C" fn f_ret_double_float_s() -> DoubleFloat {
+    DoubleFloat { f: 1., g: 2. }
+}
+
+// CHECK: define void @f_double_double_s_arg_insufficient_fprs(double %0, double %1, double %2, double %3, double %4, double %5, double %6, [2 x i64] %7)
+#[no_mangle]
+pub extern "C" fn f_double_double_s_arg_insufficient_fprs(
+    a: f64,
+    b: f64,
+    c: f64,
+    d: f64,
+    e: f64,
+    f: f64,
+    g: f64,
+    h: DoubleDouble,
+) {
+}
+
+#[repr(C)]
+pub struct DoubleInt8 {
+    f: f64,
+    i: i8,
+}
+
+#[repr(C)]
+pub struct DoubleUInt8 {
+    f: f64,
+    i: u8,
+}
+
+#[repr(C)]
+pub struct DoubleInt32 {
+    f: f64,
+    i: i32,
+}
+
+#[repr(C)]
+pub struct DoubleInt64 {
+    f: f64,
+    i: i64,
+}
+
+// CHECK: define void @f_double_int8_s_arg({ double, i8 } %0)
+#[no_mangle]
+pub extern "C" fn f_double_int8_s_arg(a: DoubleInt8) {}
+
+// CHECK: define { double, i8 } @f_ret_double_int8_s()
+#[no_mangle]
+pub extern "C" fn f_ret_double_int8_s() -> DoubleInt8 {
+    DoubleInt8 { f: 1., i: 2 }
+}
+
+// CHECK: define void @f_double_int32_s_arg({ double, i32 } %0)
+#[no_mangle]
+pub extern "C" fn f_double_int32_s_arg(a: DoubleInt32) {}
+
+// CHECK: define { double, i32 } @f_ret_double_int32_s()
+#[no_mangle]
+pub extern "C" fn f_ret_double_int32_s() -> DoubleInt32 {
+    DoubleInt32 { f: 1., i: 2 }
+}
+
+// CHECK: define void @f_double_uint8_s_arg({ double, i8 } %0)
+#[no_mangle]
+pub extern "C" fn f_double_uint8_s_arg(a: DoubleUInt8) {}
+
+// CHECK: define { double, i8 } @f_ret_double_uint8_s()
+#[no_mangle]
+pub extern "C" fn f_ret_double_uint8_s() -> DoubleUInt8 {
+    DoubleUInt8 { f: 1., i: 2 }
+}
+
+// CHECK: define void @f_double_int64_s_arg({ double, i64 } %0)
+#[no_mangle]
+pub extern "C" fn f_double_int64_s_arg(a: DoubleInt64) {}
+
+// CHECK: define { double, i64 } @f_ret_double_int64_s()
+#[no_mangle]
+pub extern "C" fn f_ret_double_int64_s() -> DoubleInt64 {
+    DoubleInt64 { f: 1., i: 2 }
+}
+
+// CHECK: define void @f_double_int8_s_arg_insufficient_gprs(i32 noundef signext %a, i32 noundef signext %b, i32 noundef signext %c, i32 noundef signext %d, i32 noundef signext %e, i32 noundef signext %f, i32 noundef signext %g, i32 noundef signext %h, [2 x i64] %0)
+#[no_mangle]
+pub extern "C" fn f_double_int8_s_arg_insufficient_gprs(
+    a: i32,
+    b: i32,
+    c: i32,
+    d: i32,
+    e: i32,
+    f: i32,
+    g: i32,
+    h: i32,
+    i: DoubleInt8,
+) {
+}
+
+// CHECK: define void @f_struct_double_int8_insufficient_fprs(float %0, double %1, double %2, double %3, double %4, double %5, double %6, double %7, [2 x i64] %8)
+#[no_mangle]
+pub extern "C" fn f_struct_double_int8_insufficient_fprs(
+    a: f32,
+    b: f64,
+    c: f64,
+    d: f64,
+    e: f64,
+    f: f64,
+    g: f64,
+    h: f64,
+    i: DoubleInt8,
+) {
+}
+
+#[repr(C)]
+pub struct DoubleArr1 {
+    a: [f64; 1],
+}
+
+// CHECK: define void @f_doublearr1_s_arg(double %0)
+#[no_mangle]
+pub extern "C" fn f_doublearr1_s_arg(a: DoubleArr1) {}
+
+// CHECK: define double @f_ret_doublearr1_s()
+#[no_mangle]
+pub extern "C" fn f_ret_doublearr1_s() -> DoubleArr1 {
+    DoubleArr1 { a: [1.] }
+}
+
+#[repr(C)]
+pub struct DoubleArr2 {
+    a: [f64; 2],
+}
+
+// CHECK: define void @f_doublearr2_s_arg({ double, double } %0)
+#[no_mangle]
+pub extern "C" fn f_doublearr2_s_arg(a: DoubleArr2) {}
+
+// CHECK: define { double, double } @f_ret_doublearr2_s()
+#[no_mangle]
+pub extern "C" fn f_ret_doublearr2_s() -> DoubleArr2 {
+    DoubleArr2 { a: [1., 2.] }
+}
+
+#[repr(C)]
+pub struct Tricky1 {
+    f: [f64; 1],
+}
+
+#[repr(C)]
+pub struct DoubleArr2Tricky1 {
+    g: [Tricky1; 2],
+}
+
+// CHECK: define void @f_doublearr2_tricky1_s_arg({ double, double } %0)
+#[no_mangle]
+pub extern "C" fn f_doublearr2_tricky1_s_arg(a: DoubleArr2Tricky1) {}
+
+// CHECK: define { double, double } @f_ret_doublearr2_tricky1_s()
+#[no_mangle]
+pub extern "C" fn f_ret_doublearr2_tricky1_s() -> DoubleArr2Tricky1 {
+    DoubleArr2Tricky1 { g: [Tricky1 { f: [1.] }, Tricky1 { f: [2.] }] }
+}
+
+#[repr(C)]
+pub struct EmptyStruct {}
+
+#[repr(C)]
+pub struct DoubleArr2Tricky2 {
+    s: EmptyStruct,
+    g: [Tricky1; 2],
+}
+
+// CHECK: define void @f_doublearr2_tricky2_s_arg({ double, double } %0)
+#[no_mangle]
+pub extern "C" fn f_doublearr2_tricky2_s_arg(a: DoubleArr2Tricky2) {}
+
+// CHECK: define { double, double } @f_ret_doublearr2_tricky2_s()
+#[no_mangle]
+pub extern "C" fn f_ret_doublearr2_tricky2_s() -> DoubleArr2Tricky2 {
+    DoubleArr2Tricky2 { s: EmptyStruct {}, g: [Tricky1 { f: [1.] }, Tricky1 { f: [2.] }] }
+}
+
+#[repr(C)]
+pub struct IntDoubleInt {
+    a: i32,
+    b: f64,
+    c: i32,
+}
+
+// CHECK: define void @f_int_double_int_s_arg(ptr noalias{{( nocapture)?}} noundef align 8{{( captures\(none\))?}} dereferenceable(24) %a)
+#[no_mangle]
+pub extern "C" fn f_int_double_int_s_arg(a: IntDoubleInt) {}
+
+// CHECK: define void @f_ret_int_double_int_s(ptr{{( dead_on_unwind)?}} noalias{{( nocapture)?}} noundef{{( writable)?}} sret([24 x i8]) align 8{{( captures\(none\))?}} dereferenceable(24) %_0)
+#[no_mangle]
+pub extern "C" fn f_ret_int_double_int_s() -> IntDoubleInt {
+    IntDoubleInt { a: 1, b: 2., c: 3 }
+}
+
+#[repr(C)]
+pub struct CharCharDouble {
+    a: u8,
+    b: u8,
+    c: f64,
+}
+
+// CHECK: define void @f_char_char_double_s_arg([2 x i64] %0)
+#[no_mangle]
+pub extern "C" fn f_char_char_double_s_arg(a: CharCharDouble) {}
+
+// CHECK: define [2 x i64] @f_ret_char_char_double_s()
+#[no_mangle]
+pub extern "C" fn f_ret_char_char_double_s() -> CharCharDouble {
+    CharCharDouble { a: 1, b: 2, c: 3. }
+}
+
+#[repr(C)]
+pub union DoubleU {
+    a: f64,
+}
+
+// CHECK: define void @f_double_u_arg(i64 %0)
+#[no_mangle]
+pub extern "C" fn f_double_u_arg(a: DoubleU) {}
+
+// CHECK: define i64 @f_ret_double_u()
+#[no_mangle]
+pub extern "C" fn f_ret_double_u() -> DoubleU {
+    unsafe { DoubleU { a: 1. } }
+}
diff --git a/tests/codegen-llvm/lto-removes-invokes.rs b/tests/codegen-llvm/lto-removes-invokes.rs
new file mode 100644
index 00000000000..3640bd1ab86
--- /dev/null
+++ b/tests/codegen-llvm/lto-removes-invokes.rs
@@ -0,0 +1,21 @@
+//@ compile-flags: -C lto -C panic=abort -Copt-level=3
+//@ no-prefer-dynamic
+
+fn main() {
+    foo();
+}
+
+#[no_mangle]
+#[inline(never)]
+fn foo() {
+    let _a = Box::new(3);
+    bar();
+    // CHECK-LABEL: define dso_local void @foo
+    // CHECK: call void @bar
+}
+
+#[inline(never)]
+#[no_mangle]
+fn bar() {
+    println!("hello!");
+}
diff --git a/tests/codegen-llvm/macos/i686-macosx-deployment-target.rs b/tests/codegen-llvm/macos/i686-macosx-deployment-target.rs
new file mode 100644
index 00000000000..cfa91e61cb0
--- /dev/null
+++ b/tests/codegen-llvm/macos/i686-macosx-deployment-target.rs
@@ -0,0 +1,23 @@
+// Checks that we correctly modify the target when MACOSX_DEPLOYMENT_TARGET is set.
+// See issue #60235.
+
+//@ add-core-stubs
+//@ compile-flags: -Copt-level=3 --target=i686-apple-darwin --crate-type=rlib
+//@ needs-llvm-components: x86
+//@ rustc-env:MACOSX_DEPLOYMENT_TARGET=10.14
+#![feature(no_core, lang_items)]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+#[repr(C)]
+pub struct Bool {
+    b: bool,
+}
+
+// CHECK: target triple = "i686-apple-macosx10.14.0"
+#[no_mangle]
+pub extern "C" fn structbool() -> Bool {
+    Bool { b: true }
+}
diff --git a/tests/codegen-llvm/macos/i686-no-macosx-deployment-target.rs b/tests/codegen-llvm/macos/i686-no-macosx-deployment-target.rs
new file mode 100644
index 00000000000..25ec5f6acbb
--- /dev/null
+++ b/tests/codegen-llvm/macos/i686-no-macosx-deployment-target.rs
@@ -0,0 +1,23 @@
+// Checks that we leave the target alone MACOSX_DEPLOYMENT_TARGET is unset.
+// See issue #60235.
+
+//@ add-core-stubs
+//@ compile-flags: -Copt-level=3 --target=i686-apple-darwin --crate-type=rlib
+//@ needs-llvm-components: x86
+//@ unset-rustc-env:MACOSX_DEPLOYMENT_TARGET
+#![feature(no_core, lang_items)]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+#[repr(C)]
+pub struct Bool {
+    b: bool,
+}
+
+// CHECK: target triple = "i686-apple-macosx10.12.0"
+#[no_mangle]
+pub extern "C" fn structbool() -> Bool {
+    Bool { b: true }
+}
diff --git a/tests/codegen-llvm/macos/x86_64-macosx-deployment-target.rs b/tests/codegen-llvm/macos/x86_64-macosx-deployment-target.rs
new file mode 100644
index 00000000000..8ea95ba0575
--- /dev/null
+++ b/tests/codegen-llvm/macos/x86_64-macosx-deployment-target.rs
@@ -0,0 +1,23 @@
+// Checks that we correctly modify the target when MACOSX_DEPLOYMENT_TARGET is set.
+// See issue #60235.
+
+//@ add-core-stubs
+//@ compile-flags: -Copt-level=3 --target=x86_64-apple-darwin --crate-type=rlib
+//@ needs-llvm-components: x86
+//@ rustc-env:MACOSX_DEPLOYMENT_TARGET=10.14
+#![feature(no_core, lang_items)]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+#[repr(C)]
+pub struct Bool {
+    b: bool,
+}
+
+// CHECK: target triple = "x86_64-apple-macosx10.14.0"
+#[no_mangle]
+pub extern "C" fn structbool() -> Bool {
+    Bool { b: true }
+}
diff --git a/tests/codegen-llvm/macos/x86_64-no-macosx-deployment-target.rs b/tests/codegen-llvm/macos/x86_64-no-macosx-deployment-target.rs
new file mode 100644
index 00000000000..474094957ae
--- /dev/null
+++ b/tests/codegen-llvm/macos/x86_64-no-macosx-deployment-target.rs
@@ -0,0 +1,23 @@
+// Checks that we leave the target alone when MACOSX_DEPLOYMENT_TARGET is unset.
+// See issue #60235.
+
+//@ add-core-stubs
+//@ compile-flags: -Copt-level=3 --target=x86_64-apple-darwin --crate-type=rlib
+//@ needs-llvm-components: x86
+//@ unset-rustc-env:MACOSX_DEPLOYMENT_TARGET
+#![feature(no_core, lang_items)]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+#[repr(C)]
+pub struct Bool {
+    b: bool,
+}
+
+// CHECK: target triple = "x86_64-apple-macosx10.12.0"
+#[no_mangle]
+pub extern "C" fn structbool() -> Bool {
+    Bool { b: true }
+}
diff --git a/tests/codegen-llvm/mainsubprogram.rs b/tests/codegen-llvm/mainsubprogram.rs
new file mode 100644
index 00000000000..ce3fe3c8608
--- /dev/null
+++ b/tests/codegen-llvm/mainsubprogram.rs
@@ -0,0 +1,12 @@
+// This test depends on a patch that was committed to upstream LLVM
+// before 4.0, formerly backported to the Rust LLVM fork.
+
+//@ ignore-apple
+//@ ignore-wasi
+
+//@ compile-flags: -g -C no-prepopulate-passes
+
+// CHECK-LABEL: @main
+// CHECK: {{.*}}DISubprogram{{.*}}name: "main",{{.*}}DI{{(SP)?}}FlagMainSubprogram{{.*}}
+
+pub fn main() {}
diff --git a/tests/codegen-llvm/match-optimized.rs b/tests/codegen-llvm/match-optimized.rs
new file mode 100644
index 00000000000..7b409e619a8
--- /dev/null
+++ b/tests/codegen-llvm/match-optimized.rs
@@ -0,0 +1,60 @@
+//@ compile-flags: -Cno-prepopulate-passes -Copt-level=3
+
+#![crate_type = "lib"]
+
+pub enum E {
+    A,
+    B,
+    C,
+}
+
+// CHECK-LABEL: @exhaustive_match
+#[no_mangle]
+pub fn exhaustive_match(e: E) -> u8 {
+    // CHECK: switch{{.*}}, label %[[OTHERWISE:[a-zA-Z0-9_]+]] [
+    // CHECK-NEXT: i[[TY:[0-9]+]] [[DISCR:[0-9]+]], label %[[A:[a-zA-Z0-9_]+]]
+    // CHECK-NEXT: i[[TY:[0-9]+]] [[DISCR:[0-9]+]], label %[[B:[a-zA-Z0-9_]+]]
+    // CHECK-NEXT: i[[TY:[0-9]+]] [[DISCR:[0-9]+]], label %[[C:[a-zA-Z0-9_]+]]
+    // CHECK-NEXT: ]
+    // CHECK: [[OTHERWISE]]:
+    // CHECK-NEXT: unreachable
+    //
+    // CHECK: [[A]]:
+    // CHECK-NEXT: store i8 0, ptr %_0, align 1
+    // CHECK-NEXT: br label %[[EXIT:[a-zA-Z0-9_]+]]
+    // CHECK: [[B]]:
+    // CHECK-NEXT: store i8 1, ptr %_0, align 1
+    // CHECK-NEXT: br label %[[EXIT]]
+    // CHECK: [[C]]:
+    // CHECK-NEXT: store i8 3, ptr %_0, align 1
+    // CHECK-NEXT: br label %[[EXIT]]
+    match e {
+        E::A => 0,
+        E::B => 1,
+        E::C => 3,
+    }
+}
+
+#[repr(u16)]
+pub enum E2 {
+    A = 13,
+    B = 42,
+}
+
+// For optimized code we produce a switch with an unreachable target as the `otherwise` so LLVM
+// knows the possible values. Compare with `tests/codegen/match-unoptimized.rs`.
+
+// CHECK-LABEL: @exhaustive_match_2
+#[no_mangle]
+pub fn exhaustive_match_2(e: E2) -> u8 {
+    // CHECK: switch i16 %{{.+}}, label %[[UNREACH:.+]] [
+    // CHECK-NEXT: i16 13,
+    // CHECK-NEXT: i16 42,
+    // CHECK-NEXT: ]
+    // CHECK: [[UNREACH]]:
+    // CHECK-NEXT: unreachable
+    match e {
+        E2::A => 0,
+        E2::B => 1,
+    }
+}
diff --git a/tests/codegen-llvm/match-optimizes-away.rs b/tests/codegen-llvm/match-optimizes-away.rs
new file mode 100644
index 00000000000..5e9be72a09f
--- /dev/null
+++ b/tests/codegen-llvm/match-optimizes-away.rs
@@ -0,0 +1,41 @@
+//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled
+#![crate_type = "lib"]
+
+pub enum Three {
+    A,
+    B,
+    C,
+}
+
+#[repr(u16)]
+pub enum Four {
+    A,
+    B,
+    C,
+    D,
+}
+
+#[no_mangle]
+pub fn three_valued(x: Three) -> Three {
+    // CHECK-LABEL: i8 @three_valued(i8{{.+}}%x)
+    // CHECK-NEXT: {{^.*:$}}
+    // CHECK-NEXT: ret i8 %x
+    match x {
+        Three::A => Three::A,
+        Three::B => Three::B,
+        Three::C => Three::C,
+    }
+}
+
+#[no_mangle]
+pub fn four_valued(x: Four) -> Four {
+    // CHECK-LABEL: i16 @four_valued(i16{{.+}}%x)
+    // CHECK-NEXT: {{^.*:$}}
+    // CHECK-NEXT: ret i16 %x
+    match x {
+        Four::A => Four::A,
+        Four::B => Four::B,
+        Four::C => Four::C,
+        Four::D => Four::D,
+    }
+}
diff --git a/tests/codegen-llvm/match-unoptimized.rs b/tests/codegen-llvm/match-unoptimized.rs
new file mode 100644
index 00000000000..3dfe78c3e16
--- /dev/null
+++ b/tests/codegen-llvm/match-unoptimized.rs
@@ -0,0 +1,23 @@
+//@ compile-flags: -C no-prepopulate-passes -Copt-level=0
+
+#![crate_type = "lib"]
+
+#[repr(u16)]
+pub enum E2 {
+    A = 13,
+    B = 42,
+}
+
+// For unoptimized code we produce a `br` instead of a `switch`. Compare with
+// `tests/codegen/match-optimized.rs`
+
+// CHECK-LABEL: @exhaustive_match_2
+#[no_mangle]
+pub fn exhaustive_match_2(e: E2) -> u8 {
+    // CHECK: %[[CMP:.+]] = icmp eq i16 %{{.+}}, 13
+    // CHECK-NEXT: br i1 %[[CMP:.+]],
+    match e {
+        E2::A => 0,
+        E2::B => 1,
+    }
+}
diff --git a/tests/codegen-llvm/maybeuninit-rvo.rs b/tests/codegen-llvm/maybeuninit-rvo.rs
new file mode 100644
index 00000000000..097aa610f1b
--- /dev/null
+++ b/tests/codegen-llvm/maybeuninit-rvo.rs
@@ -0,0 +1,34 @@
+//@ compile-flags: -Copt-level=3
+//@ needs-unwind
+#![feature(c_unwind)]
+#![crate_type = "lib"]
+
+pub struct Foo([u8; 1000]);
+
+extern "C" {
+    fn init(p: *mut Foo);
+}
+
+pub fn new_from_uninit() -> Foo {
+    // CHECK-LABEL: new_from_uninit
+    // CHECK-NOT: call void @llvm.memcpy.
+    let mut x = std::mem::MaybeUninit::uninit();
+    unsafe {
+        init(x.as_mut_ptr());
+        x.assume_init()
+    }
+}
+
+extern "C-unwind" {
+    fn init_unwind(p: *mut Foo);
+}
+
+pub fn new_from_uninit_unwind() -> Foo {
+    // CHECK-LABEL: new_from_uninit_unwind
+    // CHECK-NOT: call void @llvm.memcpy.
+    let mut x = std::mem::MaybeUninit::uninit();
+    unsafe {
+        init_unwind(x.as_mut_ptr());
+        x.assume_init()
+    }
+}
diff --git a/tests/codegen-llvm/mem-replace-big-type.rs b/tests/codegen-llvm/mem-replace-big-type.rs
new file mode 100644
index 00000000000..0b2229ba7d1
--- /dev/null
+++ b/tests/codegen-llvm/mem-replace-big-type.rs
@@ -0,0 +1,36 @@
+// This test ensures that `mem::replace::<T>` only ever calls `@llvm.memcpy`
+// with `size_of::<T>()` as the size, and never goes through any wrapper that
+// may e.g. multiply `size_of::<T>()` with a variable "count" (which is only
+// known to be `1` after inlining).
+
+//@ compile-flags: -C no-prepopulate-passes -Zinline-mir=no
+//@ ignore-std-debug-assertions
+// Reason: precondition checks in ptr::read make them a bad candidate for MIR inlining
+//@ needs-deterministic-layouts
+
+#![crate_type = "lib"]
+
+#[repr(C, align(8))]
+pub struct Big([u64; 7]);
+pub fn replace_big(dst: &mut Big, src: Big) -> Big {
+    // Back in 1.68, this emitted six `memcpy`s.
+    // `read_via_copy` in 1.69 got that down to three.
+    // `write_via_move` and nvro get this down to the essential two.
+    std::mem::replace(dst, src)
+}
+
+// NOTE(eddyb) the `CHECK-NOT`s ensure that the only calls of `@llvm.memcpy` in
+// the entire output, are the direct calls we want, from `ptr::replace`.
+
+// CHECK-NOT: call void @llvm.memcpy
+
+// For a large type, we expect exactly three `memcpy`s
+// CHECK-LABEL: define internal void @{{.+}}mem{{.+}}replace{{.+}}(ptr
+// CHECK-SAME: sret([56 x i8]){{.+}}[[RESULT:%.+]], ptr{{.+}}%dest, ptr{{.+}}%src)
+// CHECK-NOT: call void @llvm.memcpy
+// CHECK: call void @llvm.memcpy.{{.+}}(ptr align 8 [[RESULT]], ptr align 8 %dest, i{{.*}} 56, i1 false)
+// CHECK-NOT: call void @llvm.memcpy
+// CHECK: call void @llvm.memcpy.{{.+}}(ptr align 8 %dest, ptr align 8 %src, i{{.*}} 56, i1 false)
+// CHECK-NOT: call void @llvm.memcpy
+
+// CHECK-NOT: call void @llvm.memcpy
diff --git a/tests/codegen-llvm/mem-replace-simple-type.rs b/tests/codegen-llvm/mem-replace-simple-type.rs
new file mode 100644
index 00000000000..9f3c6bacb71
--- /dev/null
+++ b/tests/codegen-llvm/mem-replace-simple-type.rs
@@ -0,0 +1,54 @@
+//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes
+//@ only-x86_64 (to not worry about usize differing)
+//@ ignore-std-debug-assertions
+// Reason: precondition checks make mem::replace not a candidate for MIR inlining
+
+#![crate_type = "lib"]
+
+#[no_mangle]
+// CHECK-LABEL: @replace_usize(
+pub fn replace_usize(r: &mut usize, v: usize) -> usize {
+    // CHECK-NOT: alloca
+    // CHECK: %[[R:.+]] = load i64, ptr %r
+    // CHECK: store i64 %v, ptr %r
+    // CHECK: ret i64 %[[R]]
+    std::mem::replace(r, v)
+}
+
+#[no_mangle]
+// CHECK-LABEL: @replace_ref_str(
+pub fn replace_ref_str<'a>(r: &mut &'a str, v: &'a str) -> &'a str {
+    // CHECK-NOT: alloca
+    // CHECK: %[[A:.+]] = load ptr
+    // CHECK: %[[B:.+]] = load i64
+    // CHECK-NOT: store
+    // CHECK-NOT: load
+    // CHECK: store ptr
+    // CHECK: store i64
+    // CHECK-NOT: load
+    // CHECK-NOT: store
+    // CHECK: %[[P1:.+]] = insertvalue { ptr, i64 } poison, ptr %[[A]], 0
+    // CHECK: %[[P2:.+]] = insertvalue { ptr, i64 } %[[P1]], i64 %[[B]], 1
+    // CHECK: ret { ptr, i64 } %[[P2]]
+    std::mem::replace(r, v)
+}
+
+#[no_mangle]
+// CHECK-LABEL: @replace_short_array_3(
+// CHECK-SAME: ptr{{.+}}sret{{.+}}%[[RET:.+]], ptr{{.+}}%r, ptr{{.+}}%v
+pub fn replace_short_array_3(r: &mut [u32; 3], v: [u32; 3]) -> [u32; 3] {
+    // CHECK-NOT: alloca
+    // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[RET]], ptr align 4 %r, i64 12, i1 false)
+    // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %r, ptr align 4 %v, i64 12, i1 false)
+    std::mem::replace(r, v)
+}
+
+#[no_mangle]
+// CHECK-LABEL: @replace_short_array_4(
+// CHECK-SAME: ptr{{.+}}sret{{.+}}%[[RET:.+]], ptr{{.+}}%r, ptr{{.+}}%v
+pub fn replace_short_array_4(r: &mut [u32; 4], v: [u32; 4]) -> [u32; 4] {
+    // CHECK-NOT: alloca
+    // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[RET]], ptr align 4 %r, i64 16, i1 false)
+    // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %r, ptr align 4 %v, i64 16, i1 false)
+    std::mem::replace(r, v)
+}
diff --git a/tests/codegen-llvm/merge-functions.rs b/tests/codegen-llvm/merge-functions.rs
new file mode 100644
index 00000000000..b9d3727ce11
--- /dev/null
+++ b/tests/codegen-llvm/merge-functions.rs
@@ -0,0 +1,16 @@
+//@ revisions: O Os
+//@[Os] compile-flags: -Copt-level=s
+//@[O] compile-flags: -Copt-level=3
+#![crate_type = "lib"]
+
+// CHECK: @func{{2|1}} = {{.*}}alias{{.*}}@func{{1|2}}
+
+#[no_mangle]
+pub fn func1(c: char) -> bool {
+    c == 's' || c == 'm' || c == 'h' || c == 'd' || c == 'w'
+}
+
+#[no_mangle]
+pub fn func2(c: char) -> bool {
+    matches!(c, 's' | 'm' | 'h' | 'd' | 'w')
+}
diff --git a/tests/codegen-llvm/meta-filecheck/check-prefix.rs b/tests/codegen-llvm/meta-filecheck/check-prefix.rs
new file mode 100644
index 00000000000..98bec68627e
--- /dev/null
+++ b/tests/codegen-llvm/meta-filecheck/check-prefix.rs
@@ -0,0 +1,4 @@
+// Simple test that uses the default CHECK prefix and should always succeed.
+
+// CHECK: main
+fn main() {}
diff --git a/tests/codegen-llvm/meta-filecheck/filecheck-flags.rs b/tests/codegen-llvm/meta-filecheck/filecheck-flags.rs
new file mode 100644
index 00000000000..8e451cf4fdc
--- /dev/null
+++ b/tests/codegen-llvm/meta-filecheck/filecheck-flags.rs
@@ -0,0 +1,8 @@
+// Arguments provided via `filecheck-flags` should be passed to `filecheck`.
+
+//@ revisions: good bad
+//@ [good] filecheck-flags: --check-prefix=CUSTOM
+//@ [bad] should-fail
+
+// CUSTOM: main
+fn main() {}
diff --git a/tests/codegen-llvm/meta-filecheck/msvc-prefix-bad.rs b/tests/codegen-llvm/meta-filecheck/msvc-prefix-bad.rs
new file mode 100644
index 00000000000..f9984c74e2a
--- /dev/null
+++ b/tests/codegen-llvm/meta-filecheck/msvc-prefix-bad.rs
@@ -0,0 +1,7 @@
+// This is exactly like `msvc-prefix-good.rs`, except that it should always fail.
+
+//@ should-fail
+
+// MSVC: text that should not match
+// NONMSVC: text that should not match
+fn main() {}
diff --git a/tests/codegen-llvm/meta-filecheck/no-directives.rs b/tests/codegen-llvm/meta-filecheck/no-directives.rs
new file mode 100644
index 00000000000..2cab263604e
--- /dev/null
+++ b/tests/codegen-llvm/meta-filecheck/no-directives.rs
@@ -0,0 +1,5 @@
+// A test that doesn't include any filecheck directives should fail.
+
+//@ should-fail
+
+fn main() {}
diff --git a/tests/codegen-llvm/meta-filecheck/revision-prefix.rs b/tests/codegen-llvm/meta-filecheck/revision-prefix.rs
new file mode 100644
index 00000000000..431066e3acc
--- /dev/null
+++ b/tests/codegen-llvm/meta-filecheck/revision-prefix.rs
@@ -0,0 +1,8 @@
+// The current revision name is registered as a filecheck prefix.
+
+//@ revisions: GOOD BAD
+//@ [BAD] should-fail
+
+// GOOD: main
+// BAD: text that should not match
+fn main() {}
diff --git a/tests/codegen-llvm/method-declaration.rs b/tests/codegen-llvm/method-declaration.rs
new file mode 100644
index 00000000000..de2f96a5151
--- /dev/null
+++ b/tests/codegen-llvm/method-declaration.rs
@@ -0,0 +1,26 @@
+//@ compile-flags: -g -Cno-prepopulate-passes
+
+// Verify that we added a declaration for a method.
+
+// CHECK: define{{.*}}@method{{.*}} !dbg ![[METHOD_DEF_DBG:[0-9]+]]
+// CHECK: define{{.*}}@function{{.*}} !dbg ![[FUNC_DEF_DBG:[0-9]+]]
+
+#![crate_type = "lib"]
+
+// CHECK-DAG: ![[FOO_DBG:[0-9]+]] = !DICompositeType(tag: {{.*}} name: "Foo", {{.*}} identifier:
+pub struct Foo;
+
+impl Foo {
+    // CHECK-DAG: ![[METHOD_DEF_DBG]] = distinct !DISubprogram(name: "method"{{.*}}, scope: ![[FOO_DBG]]{{.*}}DISPFlagDefinition{{.*}}, declaration: ![[METHOD_DECL_DBG:[0-9]+]]
+    // CHECK-DAG: ![[METHOD_DECL_DBG]] = !DISubprogram(name: "method"{{.*}}, scope: ![[FOO_DBG]]
+    #[no_mangle]
+    pub fn method() {}
+}
+
+// CHECK: ![[FUNC_DEF_DBG]] = distinct !DISubprogram(name: "function"
+// CHECK-NOT: declaration
+// CHECK-SAME: DISPFlagDefinition
+// CHECK-NOT: declaration
+// CHECK-SAME: )
+#[no_mangle]
+pub fn function() {}
diff --git a/tests/codegen-llvm/min-function-alignment.rs b/tests/codegen-llvm/min-function-alignment.rs
new file mode 100644
index 00000000000..ea5f957e81f
--- /dev/null
+++ b/tests/codegen-llvm/min-function-alignment.rs
@@ -0,0 +1,48 @@
+//@ revisions: align16 align1024
+//@ compile-flags: -C no-prepopulate-passes -Z mir-opt-level=0 -Clink-dead-code
+//@ [align16] compile-flags: -Zmin-function-alignment=16
+//@ [align1024] compile-flags: -Zmin-function-alignment=1024
+//@ ignore-wasm32 aligning functions is not currently supported on wasm (#143368)
+
+#![crate_type = "lib"]
+// FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity
+#![feature(rustc_attrs)]
+#![feature(fn_align)]
+
+// Functions without explicit alignment use the global minimum.
+//
+// NOTE: this function deliberately has zero (0) attributes! That is to make sure that
+// `-Zmin-function-alignment` is applied regardless of whether attributes are used.
+//
+// CHECK-LABEL: no_explicit_align
+// align16: align 16
+// align1024: align 1024
+pub fn no_explicit_align() {}
+
+// CHECK-LABEL: @lower_align
+// align16: align 16
+// align1024: align 1024
+#[no_mangle]
+#[rustc_align(8)]
+pub fn lower_align() {}
+
+// the higher value of min-function-alignment and the align attribute wins out
+//
+// CHECK-LABEL: @higher_align
+// align16: align 32
+// align1024: align 1024
+#[no_mangle]
+#[rustc_align(32)]
+pub fn higher_align() {}
+
+// cold functions follow the same rules as other functions
+//
+// in GCC, the `-falign-functions` does not apply to cold functions, but
+// `-Zmin-function-alignment` applies to all functions.
+//
+// CHECK-LABEL: @no_explicit_align_cold
+// align16: align 16
+// align1024: align 1024
+#[no_mangle]
+#[cold]
+pub fn no_explicit_align_cold() {}
diff --git a/tests/codegen-llvm/mir-aggregate-no-alloca.rs b/tests/codegen-llvm/mir-aggregate-no-alloca.rs
new file mode 100644
index 00000000000..77d367ed5da
--- /dev/null
+++ b/tests/codegen-llvm/mir-aggregate-no-alloca.rs
@@ -0,0 +1,137 @@
+// 32-bit systems will return 128bit values using a return area pointer.
+//@ revisions: bit32 bit64
+//@[bit32] only-32bit
+//@[bit64] only-64bit
+//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes -Z randomize-layout=no
+
+#![crate_type = "lib"]
+
+#[repr(transparent)]
+pub struct Transparent32(u32);
+
+// CHECK: i32 @make_transparent(i32{{.*}} %x)
+#[no_mangle]
+pub fn make_transparent(x: u32) -> Transparent32 {
+    // CHECK-NOT: alloca
+    // CHECK: ret i32 %x
+    let a = Transparent32(x);
+    a
+}
+
+// CHECK: i32 @make_closure(i32{{.*}} %x)
+#[no_mangle]
+pub fn make_closure(x: i32) -> impl Fn(i32) -> i32 {
+    // CHECK-NOT: alloca
+    // CHECK: ret i32 %x
+    move |y| x + y
+}
+
+#[repr(transparent)]
+pub struct TransparentPair((), (u16, u16), ());
+
+// CHECK: { i16, i16 } @make_transparent_pair(i16 noundef %x.0, i16 noundef %x.1)
+#[no_mangle]
+pub fn make_transparent_pair(x: (u16, u16)) -> TransparentPair {
+    // CHECK-NOT: alloca
+    // CHECK: %[[TEMP0:.+]] = insertvalue { i16, i16 } poison, i16 %x.0, 0
+    // CHECK: %[[TEMP1:.+]] = insertvalue { i16, i16 } %[[TEMP0]], i16 %x.1, 1
+    // CHECK: ret { i16, i16 } %[[TEMP1]]
+    let a = TransparentPair((), x, ());
+    a
+}
+
+// CHECK-LABEL: { i32, i32 } @make_2_tuple(i32{{.*}} %x)
+#[no_mangle]
+pub fn make_2_tuple(x: u32) -> (u32, u32) {
+    // CHECK-NOT: alloca
+    // CHECK: %[[TEMP0:.+]] = insertvalue { i32, i32 } poison, i32 %x, 0
+    // CHECK: %[[TEMP1:.+]] = insertvalue { i32, i32 } %[[TEMP0]], i32 %x, 1
+    // CHECK: ret { i32, i32 } %[[TEMP1]]
+    let pair = (x, x);
+    pair
+}
+
+// CHECK-LABEL: i8 @make_cell_of_bool(i1 noundef zeroext %b)
+#[no_mangle]
+pub fn make_cell_of_bool(b: bool) -> std::cell::Cell<bool> {
+    // CHECK: %[[BYTE:.+]] = zext i1 %b to i8
+    // CHECK: ret i8 %[[BYTE]]
+    std::cell::Cell::new(b)
+}
+
+// CHECK-LABEL: { i8, i16 } @make_cell_of_bool_and_short(i1 noundef zeroext %b, i16{{.*}} %s)
+#[no_mangle]
+pub fn make_cell_of_bool_and_short(b: bool, s: u16) -> std::cell::Cell<(bool, u16)> {
+    // CHECK-NOT: alloca
+    // CHECK: %[[BYTE:.+]] = zext i1 %b to i8
+    // CHECK: %[[TEMP0:.+]] = insertvalue { i8, i16 } poison, i8 %[[BYTE]], 0
+    // CHECK: %[[TEMP1:.+]] = insertvalue { i8, i16 } %[[TEMP0]], i16 %s, 1
+    // CHECK: ret { i8, i16 } %[[TEMP1]]
+    std::cell::Cell::new((b, s))
+}
+
+// CHECK-LABEL: { i1, i1 } @make_tuple_of_bools(i1 noundef zeroext %a, i1 noundef zeroext %b)
+#[no_mangle]
+pub fn make_tuple_of_bools(a: bool, b: bool) -> (bool, bool) {
+    // CHECK-NOT: alloca
+    // CHECK: %[[TEMP0:.+]] = insertvalue { i1, i1 } poison, i1 %a, 0
+    // CHECK: %[[TEMP1:.+]] = insertvalue { i1, i1 } %[[TEMP0]], i1 %b, 1
+    // CHECK: ret { i1, i1 } %[[TEMP1]]
+    (a, b)
+}
+
+pub struct Struct0();
+
+// CHECK-LABEL: void @make_struct_0()
+#[no_mangle]
+pub fn make_struct_0() -> Struct0 {
+    // CHECK: ret void
+    let s = Struct0();
+    s
+}
+
+pub struct Struct1(i32);
+
+// CHECK-LABEL: i32 @make_struct_1(i32{{.*}} %a)
+#[no_mangle]
+pub fn make_struct_1(a: i32) -> Struct1 {
+    // CHECK: ret i32 %a
+    let s = Struct1(a);
+    s
+}
+
+pub struct Struct2Asc(i16, i64);
+
+// bit32-LABEL: void @make_struct_2_asc({{.*}} sret({{[^,]*}}) {{.*}} %s,
+// bit64-LABEL: { i64, i16 } @make_struct_2_asc(
+// CHECK-SAME: i16{{.*}} %a, i64 noundef %b)
+#[no_mangle]
+pub fn make_struct_2_asc(a: i16, b: i64) -> Struct2Asc {
+    // CHECK-NOT: alloca
+    // bit32: %[[GEP:.+]] = getelementptr inbounds i8, ptr %s, i32 8
+    // bit32: store i16 %a, ptr %[[GEP]]
+    // bit32: store i64 %b, ptr %s
+    // bit64: %[[TEMP0:.+]] = insertvalue { i64, i16 } poison, i64 %b, 0
+    // bit64: %[[TEMP1:.+]] = insertvalue { i64, i16 } %[[TEMP0]], i16 %a, 1
+    // bit64: ret { i64, i16 } %[[TEMP1]]
+    let s = Struct2Asc(a, b);
+    s
+}
+
+pub struct Struct2Desc(i64, i16);
+
+// bit32-LABEL: void @make_struct_2_desc({{.*}} sret({{[^,]*}}) {{.*}} %s,
+// bit64-LABEL: { i64, i16 } @make_struct_2_desc(
+// CHECK-SAME: i64 noundef %a, i16{{.*}} %b)
+#[no_mangle]
+pub fn make_struct_2_desc(a: i64, b: i16) -> Struct2Desc {
+    // CHECK-NOT: alloca
+    // bit32: store i64 %a, ptr %s
+    // bit32: %[[GEP:.+]] = getelementptr inbounds i8, ptr %s, i32 8
+    // bit32: store i16 %b, ptr %[[GEP]]
+    // bit64: %[[TEMP0:.+]] = insertvalue { i64, i16 } poison, i64 %a, 0
+    // bit64: %[[TEMP1:.+]] = insertvalue { i64, i16 } %[[TEMP0]], i16 %b, 1
+    // bit64: ret { i64, i16 } %[[TEMP1]]
+    let s = Struct2Desc(a, b);
+    s
+}
diff --git a/tests/codegen-llvm/mir-inlined-line-numbers.rs b/tests/codegen-llvm/mir-inlined-line-numbers.rs
new file mode 100644
index 00000000000..cfe43a6cf89
--- /dev/null
+++ b/tests/codegen-llvm/mir-inlined-line-numbers.rs
@@ -0,0 +1,25 @@
+//@ compile-flags: -Copt-level=3 -g
+
+#![crate_type = "lib"]
+
+#[inline(always)]
+fn foo() {
+    bar();
+}
+
+#[inline(never)]
+#[no_mangle]
+fn bar() {
+    panic!();
+}
+
+#[no_mangle]
+pub fn example() {
+    foo();
+}
+
+// CHECK-LABEL: @example
+// CHECK:   tail call void @bar(){{( #[0-9]+)?}}, !dbg [[DBG_ID:![0-9]+]]
+// CHECK: [[DBG_ID]] = !DILocation(line: 7,
+// CHECK-SAME:                     inlinedAt: [[INLINE_ID:![0-9]+]])
+// CHECK: [[INLINE_ID]] = !DILocation(line: 18,
diff --git a/tests/codegen-llvm/mir_zst_stores.rs b/tests/codegen-llvm/mir_zst_stores.rs
new file mode 100644
index 00000000000..ff1d429cffd
--- /dev/null
+++ b/tests/codegen-llvm/mir_zst_stores.rs
@@ -0,0 +1,19 @@
+//@ compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+use std::marker::PhantomData;
+
+#[derive(Copy, Clone)]
+struct Zst {
+    phantom: PhantomData<Zst>,
+}
+
+// CHECK-LABEL: @mir
+// CHECK-NOT: store{{.*}}undef
+#[no_mangle]
+pub fn mir() {
+    let x = Zst { phantom: PhantomData };
+    let y = (x, 0);
+    drop(y);
+    drop((0, x));
+}
diff --git a/tests/codegen-llvm/move-before-nocapture-ref-arg.rs b/tests/codegen-llvm/move-before-nocapture-ref-arg.rs
new file mode 100644
index 00000000000..2ebd645e1c3
--- /dev/null
+++ b/tests/codegen-llvm/move-before-nocapture-ref-arg.rs
@@ -0,0 +1,21 @@
+// Verify that move before the call of the function with noalias, nocapture, readonly.
+// #107436
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+
+#[repr(C)]
+pub struct ThreeSlices<'a>(&'a [u32], &'a [u32], &'a [u32]);
+
+#[no_mangle]
+pub fn sum_slices(val: ThreeSlices) -> u32 {
+    // CHECK-NOT: memcpy
+    let val = val;
+    sum(&val)
+}
+
+#[no_mangle]
+#[inline(never)]
+pub fn sum(val: &ThreeSlices) -> u32 {
+    val.0.iter().sum::<u32>() + val.1.iter().sum::<u32>() + val.2.iter().sum::<u32>()
+}
diff --git a/tests/codegen-llvm/move-operands.rs b/tests/codegen-llvm/move-operands.rs
new file mode 100644
index 00000000000..ddad231b762
--- /dev/null
+++ b/tests/codegen-llvm/move-operands.rs
@@ -0,0 +1,13 @@
+// Verify that optimized MIR only copies `a` once.
+//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+type T = [u8; 256];
+
+#[no_mangle]
+pub fn f(a: T, b: fn(_: T, _: T)) {
+    // CHECK: call void @llvm.memcpy.{{.*}}(ptr align 1 %{{.*}}, ptr align 1 %{{.*}}, {{.*}} 256, i1 false)
+    // CHECK-NOT: call void @llvm.memcpy.{{.*}}(ptr align 1 %{{.*}}, ptr align 1 %{{.*}}, {{.*}} 256, i1 false)
+    b(a, a)
+}
diff --git a/tests/codegen-llvm/naked-asan.rs b/tests/codegen-llvm/naked-asan.rs
new file mode 100644
index 00000000000..46218cf79d6
--- /dev/null
+++ b/tests/codegen-llvm/naked-asan.rs
@@ -0,0 +1,30 @@
+//@ add-core-stubs
+//@ needs-llvm-components: x86
+//@ compile-flags: --target x86_64-unknown-linux-gnu -Zsanitizer=address -Ctarget-feature=-crt-static
+
+// Make sure we do not request sanitizers for naked functions.
+
+#![crate_type = "lib"]
+#![feature(no_core)]
+#![no_std]
+#![no_core]
+#![feature(abi_x86_interrupt)]
+
+extern crate minicore;
+use minicore::*;
+
+#[no_mangle]
+pub fn caller() {
+    unsafe { asm!("call {}", sym page_fault_handler) }
+}
+
+// CHECK: declare x86_intrcc void @page_fault_handler(){{.*}}#[[ATTRS:[0-9]+]]
+#[unsafe(naked)]
+#[no_mangle]
+pub extern "x86-interrupt" fn page_fault_handler() {
+    naked_asm!("ud2")
+}
+
+// CHECK: #[[ATTRS]] =
+// CHECK-NOT: sanitize_address
+// CHECK: !llvm.module.flags
diff --git a/tests/codegen-llvm/naked-fn/aligned.rs b/tests/codegen-llvm/naked-fn/aligned.rs
new file mode 100644
index 00000000000..d7281c4219a
--- /dev/null
+++ b/tests/codegen-llvm/naked-fn/aligned.rs
@@ -0,0 +1,21 @@
+//@ compile-flags: -C no-prepopulate-passes -Copt-level=0
+//@ needs-asm-support
+//@ ignore-arm no "ret" mnemonic
+//@ ignore-wasm32 aligning functions is not currently supported on wasm (#143368)
+
+#![crate_type = "lib"]
+// FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity
+#![feature(rustc_attrs)]
+#![feature(fn_align)]
+
+use std::arch::naked_asm;
+
+// CHECK: .balign 16
+// CHECK-LABEL: naked_empty:
+#[rustc_align(16)]
+#[no_mangle]
+#[unsafe(naked)]
+pub extern "C" fn naked_empty() {
+    // CHECK: ret
+    naked_asm!("ret")
+}
diff --git a/tests/codegen-llvm/naked-fn/generics.rs b/tests/codegen-llvm/naked-fn/generics.rs
new file mode 100644
index 00000000000..865be00d91e
--- /dev/null
+++ b/tests/codegen-llvm/naked-fn/generics.rs
@@ -0,0 +1,111 @@
+//@ compile-flags: -Copt-level=3
+//@ only-x86_64
+
+#![crate_type = "lib"]
+
+use std::arch::naked_asm;
+
+#[no_mangle]
+fn test(x: u64) {
+    // just making sure these symbols get used
+    using_const_generics::<1>(x);
+    using_const_generics::<2>(x);
+
+    generic_function::<i64>(x as i64);
+
+    let foo = Foo(x);
+
+    foo.method();
+    foo.trait_method();
+}
+
+// CHECK: .balign 4
+// CHECK: add rax, 2
+// CHECK: add rax, 42
+
+// CHECK: .balign 4
+// CHECK: add rax, 1
+// CHECK: add rax, 42
+
+#[unsafe(naked)]
+pub extern "C" fn using_const_generics<const N: u64>(x: u64) -> u64 {
+    const M: u64 = 42;
+
+    naked_asm!(
+        "xor rax, rax",
+        "add rax, rdi",
+        "add rax, {}",
+        "add rax, {}",
+        "ret",
+        const N,
+        const M,
+    )
+}
+
+trait Invert {
+    fn invert(self) -> Self;
+}
+
+impl Invert for i64 {
+    fn invert(self) -> Self {
+        -1 * self
+    }
+}
+
+// CHECK: .balign 4
+// CHECK-LABEL: generic_function:
+// CHECK: call
+// CHECK: ret
+
+#[unsafe(naked)]
+#[no_mangle]
+pub extern "C" fn generic_function<T: Invert>(x: i64) -> i64 {
+    naked_asm!(
+        "call {}",
+        "ret",
+        sym <T as Invert>::invert,
+    )
+}
+
+#[derive(Copy, Clone)]
+#[repr(transparent)]
+struct Foo(u64);
+
+// CHECK: .balign 4
+// CHECK-LABEL: method:
+// CHECK: mov rax, rdi
+
+impl Foo {
+    #[unsafe(naked)]
+    #[no_mangle]
+    extern "C" fn method(self) -> u64 {
+        naked_asm!("mov rax, rdi", "ret")
+    }
+}
+
+// CHECK: .balign 4
+// CHECK-LABEL: trait_method:
+// CHECK: mov rax, rdi
+
+trait Bar {
+    extern "C" fn trait_method(self) -> u64;
+}
+
+impl Bar for Foo {
+    #[unsafe(naked)]
+    #[no_mangle]
+    extern "C" fn trait_method(self) -> u64 {
+        naked_asm!("mov rax, rdi", "ret")
+    }
+}
+
+// CHECK: .balign 4
+// CHECK-LABEL: naked_with_args_and_return:
+// CHECK: lea rax, [rdi + rsi]
+
+// this previously ICE'd, see https://github.com/rust-lang/rust/issues/124375
+#[unsafe(naked)]
+#[no_mangle]
+pub unsafe extern "C" fn naked_with_args_and_return(a: isize, b: isize) -> isize {
+    naked_asm!("lea rax, [rdi + rsi]", "ret");
+}
diff --git a/tests/codegen-llvm/naked-fn/instruction-set.rs b/tests/codegen-llvm/naked-fn/instruction-set.rs
new file mode 100644
index 00000000000..67560c5aba7
--- /dev/null
+++ b/tests/codegen-llvm/naked-fn/instruction-set.rs
@@ -0,0 +1,53 @@
+//@ add-core-stubs
+//@ revisions: arm-mode thumb-mode
+//@ [arm-mode] compile-flags: --target armv5te-none-eabi
+//@ [thumb-mode] compile-flags: --target thumbv5te-none-eabi
+//@ [arm-mode] needs-llvm-components: arm
+//@ [thumb-mode] needs-llvm-components: arm
+
+#![crate_type = "lib"]
+#![feature(no_core, lang_items, rustc_attrs)]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+// arm-mode: .arm
+// thumb-mode: .thumb
+// CHECK-LABEL: test_unspecified:
+// CHECK: bx lr
+// CHECK: .popsection
+// arm-mode: .arm
+// thumb-mode: .thumb
+#[no_mangle]
+#[unsafe(naked)]
+extern "C" fn test_unspecified() {
+    naked_asm!("bx lr");
+}
+
+// CHECK: .thumb
+// CHECK: .thumb_func
+// CHECK-LABEL: test_thumb:
+// CHECK: bx lr
+// CHECK: .popsection
+// arm-mode: .arm
+// thumb-mode: .thumb
+#[no_mangle]
+#[unsafe(naked)]
+#[instruction_set(arm::t32)]
+extern "C" fn test_thumb() {
+    naked_asm!("bx lr");
+}
+
+// CHECK: .arm
+// CHECK-LABEL: test_arm:
+// CHECK: bx lr
+// CHECK: .popsection
+// arm-mode: .arm
+// thumb-mode: .thumb
+#[no_mangle]
+#[unsafe(naked)]
+#[instruction_set(arm::a32)]
+extern "C" fn test_arm() {
+    naked_asm!("bx lr");
+}
diff --git a/tests/codegen-llvm/naked-fn/min-function-alignment.rs b/tests/codegen-llvm/naked-fn/min-function-alignment.rs
new file mode 100644
index 00000000000..406e9334fa5
--- /dev/null
+++ b/tests/codegen-llvm/naked-fn/min-function-alignment.rs
@@ -0,0 +1,47 @@
+//@ compile-flags: -C no-prepopulate-passes -Copt-level=0 -Zmin-function-alignment=16
+//@ needs-asm-support
+//@ ignore-arm no "ret" mnemonic
+//@ ignore-wasm32 aligning functions is not currently supported on wasm (#143368)
+
+// FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity
+#![feature(rustc_attrs)]
+#![feature(fn_align)]
+#![crate_type = "lib"]
+
+// functions without explicit alignment use the global minimum
+//
+// CHECK: .balign 16
+#[no_mangle]
+#[unsafe(naked)]
+pub extern "C" fn naked_no_explicit_align() {
+    core::arch::naked_asm!("ret")
+}
+
+// CHECK: .balign 16
+#[no_mangle]
+#[rustc_align(8)]
+#[unsafe(naked)]
+pub extern "C" fn naked_lower_align() {
+    core::arch::naked_asm!("ret")
+}
+
+// CHECK: .balign 32
+#[no_mangle]
+#[rustc_align(32)]
+#[unsafe(naked)]
+pub extern "C" fn naked_higher_align() {
+    core::arch::naked_asm!("ret")
+}
+
+// cold functions follow the same rules as other functions
+//
+// in GCC, the `-falign-functions` does not apply to cold functions, but
+// `-Zmin-function-alignment` applies to all functions.
+//
+// CHECK: .balign 16
+#[no_mangle]
+#[cold]
+#[unsafe(naked)]
+pub extern "C" fn no_explicit_align_cold() {
+    core::arch::naked_asm!("ret")
+}
diff --git a/tests/codegen-llvm/naked-fn/naked-functions.rs b/tests/codegen-llvm/naked-fn/naked-functions.rs
new file mode 100644
index 00000000000..344af6eb42f
--- /dev/null
+++ b/tests/codegen-llvm/naked-fn/naked-functions.rs
@@ -0,0 +1,165 @@
+//@ add-core-stubs
+//@ revisions: linux win_x86 win_i686 macos thumb
+//
+//@[linux] compile-flags: --target x86_64-unknown-linux-gnu
+//@[linux] needs-llvm-components: x86
+//@[win_x86] compile-flags: --target x86_64-pc-windows-gnu
+//@[win_x86] needs-llvm-components: x86
+//@[win_i686] compile-flags: --target i686-pc-windows-gnu
+//@[win_i686] needs-llvm-components: x86
+//@[macos] compile-flags: --target aarch64-apple-darwin
+//@[macos] needs-llvm-components: arm
+//@[thumb] compile-flags: --target thumbv7em-none-eabi
+//@[thumb] needs-llvm-components: arm
+
+#![crate_type = "lib"]
+#![feature(no_core, lang_items, rustc_attrs)]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+// linux,win: .intel_syntax
+//
+// linux:    .pushsection .text.naked_empty,\22ax\22, @progbits
+// macos:    .pushsection __TEXT,__text,regular,pure_instructions
+// win_x86:  .pushsection .text.naked_empty,\22xr\22
+// win_i686: .pushsection .text._naked_empty,\22xr\22
+// thumb:    .pushsection .text.naked_empty,\22ax\22, %progbits
+//
+// CHECK: .balign 4
+//
+// linux,win,thumb: .globl naked_empty
+// macos: .globl _naked_empty
+//
+// CHECK-NOT: .private_extern
+// CHECK-NOT: .hidden
+//
+// linux: .type naked_empty, @function
+//
+// win_x86:  .def naked_empty
+// win_i686: .def _naked_empty
+//
+// win_x86,win_i686: .scl 2
+// win_x86,win_i686: .type 32
+// win_x86,win_i686: .endef
+//
+// thumb: .type naked_empty, %function
+// thumb: .thumb
+// thumb: .thumb_func
+//
+// CHECK-LABEL: naked_empty:
+//
+// linux,macos,win: ret
+// thumb: bx lr
+//
+// CHECK: .popsection
+//
+// thumb: .thumb
+//
+// linux,win: .att_syntax
+
+#[no_mangle]
+#[unsafe(naked)]
+pub extern "C" fn naked_empty() {
+    #[cfg(not(all(target_arch = "arm", target_feature = "thumb-mode")))]
+    naked_asm!("ret");
+
+    #[cfg(all(target_arch = "arm", target_feature = "thumb-mode"))]
+    naked_asm!("bx lr");
+}
+
+// linux,win: .intel_syntax
+//
+// linux:    .pushsection .text.naked_with_args_and_return,\22ax\22, @progbits
+// macos:    .pushsection __TEXT,__text,regular,pure_instructions
+// win_x86:  .pushsection .text.naked_with_args_and_return,\22xr\22
+// win_i686: .pushsection .text._naked_with_args_and_return,\22xr\22
+// thumb:    .pushsection .text.naked_with_args_and_return,\22ax\22, %progbits
+//
+// CHECK: .balign 4
+//
+// linux,win,thumb: .globl naked_with_args_and_return
+// macos: .globl _naked_with_args_and_return
+//
+// CHECK-NOT: .private_extern
+// CHECK-NOT: .hidden
+//
+// linux: .type naked_with_args_and_return, @function
+//
+// win_x86:  .def naked_with_args_and_return
+// win_i686: .def _naked_with_args_and_return
+//
+// win_x86,win_i686: .scl 2
+// win_x86,win_i686: .type 32
+// win_x86,win_i686: .endef
+//
+// thumb: .type naked_with_args_and_return, %function
+// thumb: .thumb
+// thumb: .thumb_func
+//
+// CHECK-LABEL: naked_with_args_and_return:
+//
+// linux, win_x86,win_i686: lea rax, [rdi + rsi]
+// macos: add x0, x0, x1
+// thumb: adds r0, r0, r1
+//
+// linux,macos,win: ret
+// thumb: bx lr
+//
+// CHECK: .popsection
+//
+// thumb: .thumb
+//
+// linux,win: .att_syntax
+
+#[no_mangle]
+#[unsafe(naked)]
+pub extern "C" fn naked_with_args_and_return(a: isize, b: isize) -> isize {
+    #[cfg(any(target_os = "windows", target_os = "linux"))]
+    {
+        naked_asm!("lea rax, [rdi + rsi]", "ret")
+    }
+
+    #[cfg(target_os = "macos")]
+    {
+        naked_asm!("add x0, x0, x1", "ret")
+    }
+
+    #[cfg(all(target_arch = "arm", target_feature = "thumb-mode"))]
+    {
+        naked_asm!("adds r0, r0, r1", "bx lr")
+    }
+}
+
+// linux:            .pushsection .text.some_different_name,\22ax\22, @progbits
+// macos:            .pushsection .text.some_different_name,regular,pure_instructions
+// win_x86,win_i686: .pushsection .text.some_different_name,\22xr\22
+// thumb:            .pushsection .text.some_different_name,\22ax\22, %progbits
+// CHECK-LABEL: test_link_section:
+#[no_mangle]
+#[unsafe(naked)]
+#[link_section = ".text.some_different_name"]
+pub extern "C" fn test_link_section() {
+    #[cfg(not(all(target_arch = "arm", target_feature = "thumb-mode")))]
+    naked_asm!("ret");
+
+    #[cfg(all(target_arch = "arm", target_feature = "thumb-mode"))]
+    naked_asm!("bx lr");
+}
+
+// win_x86:  .def fastcall_cc
+// win_i686: .def @fastcall_cc@4
+//
+// win_x86,win_i686: .scl 2
+// win_x86,win_i686: .type 32
+// win_x86,win_i686: .endef
+//
+// win_x86-LABEL: fastcall_cc:
+// win_i686-LABEL: @fastcall_cc@4:
+#[cfg(target_os = "windows")]
+#[no_mangle]
+#[unsafe(naked)]
+pub extern "fastcall" fn fastcall_cc(x: i32) -> i32 {
+    naked_asm!("ret");
+}
diff --git a/tests/codegen-llvm/no-alloca-inside-if-false.rs b/tests/codegen-llvm/no-alloca-inside-if-false.rs
new file mode 100644
index 00000000000..a231c7e808a
--- /dev/null
+++ b/tests/codegen-llvm/no-alloca-inside-if-false.rs
@@ -0,0 +1,27 @@
+//@ compile-flags: -Cno-prepopulate-passes -Copt-level=0 -Cpanic=abort
+// Check that there's an alloca for the reference and the vector, but nothing else.
+// We use panic=abort because unwinding panics give hint::black_box a cleanup block, which has
+// another alloca.
+
+#![crate_type = "lib"]
+
+#[inline(never)]
+fn test<const SIZE: usize>() {
+    // CHECK-LABEL: no_alloca_inside_if_false::test
+    // CHECK: start:
+    // CHECK-NEXT: alloca [{{12|24}} x i8]
+    // CHECK-NOT: alloca
+    if const { SIZE < 4096 } {
+        let arr = [0u8; SIZE];
+        std::hint::black_box(&arr);
+    } else {
+        let vec = vec![0u8; SIZE];
+        std::hint::black_box(&vec);
+    }
+}
+
+// CHECK-LABEL: @main
+#[no_mangle]
+pub fn main() {
+    test::<8192>();
+}
diff --git a/tests/codegen-llvm/no-assumes-on-casts.rs b/tests/codegen-llvm/no-assumes-on-casts.rs
new file mode 100644
index 00000000000..9c00dc2c015
--- /dev/null
+++ b/tests/codegen-llvm/no-assumes-on-casts.rs
@@ -0,0 +1,19 @@
+#![crate_type = "lib"]
+
+//@ compile-flags: -Cno-prepopulate-passes
+
+// CHECK-LABEL: fna
+#[no_mangle]
+pub fn fna(a: i16) -> i32 {
+    a as i32
+    // CHECK-NOT: assume
+    // CHECK: sext
+}
+
+// CHECK-LABEL: fnb
+#[no_mangle]
+pub fn fnb(a: u16) -> u32 {
+    a as u32
+    // CHECK-NOT: assume
+    // CHECK: zext
+}
diff --git a/tests/codegen-llvm/no-dllimport-w-cross-lang-lto.rs b/tests/codegen-llvm/no-dllimport-w-cross-lang-lto.rs
new file mode 100644
index 00000000000..c71eddfa287
--- /dev/null
+++ b/tests/codegen-llvm/no-dllimport-w-cross-lang-lto.rs
@@ -0,0 +1,13 @@
+// This test makes sure that functions get annotated with the proper
+// "target-cpu" attribute in LLVM.
+
+//@ no-prefer-dynamic
+//@ only-msvc
+//@ compile-flags: -C linker-plugin-lto
+
+#![crate_type = "rlib"]
+
+// CHECK-NOT: @{{.*}}__imp_{{.*}}GLOBAL{{.*}} = global i8*
+
+pub static GLOBAL: u32 = 0;
+pub static mut GLOBAL2: u32 = 0;
diff --git a/tests/codegen-llvm/no-jump-tables.rs b/tests/codegen-llvm/no-jump-tables.rs
new file mode 100644
index 00000000000..e49de7e9dc1
--- /dev/null
+++ b/tests/codegen-llvm/no-jump-tables.rs
@@ -0,0 +1,23 @@
+// Test that the `no-jump-tables` function attribute are (not) emitted when
+// the `-Zno-jump-tables` flag is (not) set.
+
+//@ add-core-stubs
+//@ revisions: unset set
+//@ needs-llvm-components: x86
+//@ compile-flags: --target x86_64-unknown-linux-gnu
+//@ [set] compile-flags: -Zno-jump-tables
+
+#![crate_type = "lib"]
+#![feature(no_core, lang_items)]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+#[no_mangle]
+pub fn foo() {
+    // CHECK: @foo() unnamed_addr #0
+
+    // unset-NOT: attributes #0 = { {{.*}}"no-jump-tables"="true"{{.*}} }
+    // set: attributes #0 = { {{.*}}"no-jump-tables"="true"{{.*}} }
+}
diff --git a/tests/codegen-llvm/no-plt.rs b/tests/codegen-llvm/no-plt.rs
new file mode 100644
index 00000000000..3a3546ff7c4
--- /dev/null
+++ b/tests/codegen-llvm/no-plt.rs
@@ -0,0 +1,17 @@
+//@ compile-flags: -C relocation-model=pic -Z plt=no
+
+#![crate_type = "lib"]
+
+// We need a function which is normally called through the PLT.
+extern "C" {
+    // CHECK: Function Attrs:{{.*}}nonlazybind
+    fn getenv(name: *const u8) -> *mut u8;
+}
+
+// Ensure the function gets referenced.
+pub unsafe fn call_through_plt() -> *mut u8 {
+    getenv(b"\0".as_ptr())
+}
+
+// Ensure intrinsics also skip the PLT
+// CHECK: !"RtLibUseGOT"
diff --git a/tests/codegen-llvm/no-redundant-item-monomorphization.rs b/tests/codegen-llvm/no-redundant-item-monomorphization.rs
new file mode 100644
index 00000000000..466037c3770
--- /dev/null
+++ b/tests/codegen-llvm/no-redundant-item-monomorphization.rs
@@ -0,0 +1,33 @@
+// Test to make sure that inner functions within a polymorphic outer function
+// don't get re-codegened when the outer function is monomorphized. The test
+// code monomorphizes the outer functions several times, but the magic constants
+// used in the inner functions should each appear only once in the generated IR.
+
+// issue: rust-lang/rust#7349
+//@ compile-flags: -Cno-prepopulate-passes -Copt-level=0
+
+// CHECK-COUNT-1: ret i32 8675309
+// CHECK-COUNT-1: ret i32 11235813
+
+fn outer<T>() {
+    #[allow(dead_code)]
+    fn inner() -> u32 {
+        8675309
+    }
+    inner();
+}
+
+extern "C" fn outer_foreign<T>() {
+    #[allow(dead_code)]
+    fn inner() -> u32 {
+        11235813
+    }
+    inner();
+}
+
+fn main() {
+    outer::<isize>();
+    outer::<usize>();
+    outer_foreign::<isize>();
+    outer_foreign::<usize>();
+}
diff --git a/tests/codegen-llvm/no_builtins-at-crate.rs b/tests/codegen-llvm/no_builtins-at-crate.rs
new file mode 100644
index 00000000000..ba1d31f60c3
--- /dev/null
+++ b/tests/codegen-llvm/no_builtins-at-crate.rs
@@ -0,0 +1,24 @@
+//@ compile-flags: -C opt-level=1
+
+#![no_builtins]
+#![crate_type = "lib"]
+
+// CHECK: define
+// CHECK-SAME: @__aeabi_memcpy
+// CHECK-SAME: #0
+#[no_mangle]
+pub unsafe extern "C" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, size: usize) {
+    // CHECK: call
+    // CHECK-SAME: @memcpy(
+    memcpy(dest, src, size);
+}
+
+// CHECK: declare
+// CHECK-SAME: @memcpy
+// CHECK-SAME: #0
+extern "C" {
+    pub fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8;
+}
+
+// CHECK: attributes #0
+// CHECK-SAME: "no-builtins"
diff --git a/tests/codegen-llvm/noalias-box-off.rs b/tests/codegen-llvm/noalias-box-off.rs
new file mode 100644
index 00000000000..664c7950280
--- /dev/null
+++ b/tests/codegen-llvm/noalias-box-off.rs
@@ -0,0 +1,11 @@
+//@ compile-flags: -Copt-level=3 -Z box-noalias=no
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @box_should_not_have_noalias_if_disabled(
+// CHECK-NOT: noalias
+// CHECK-SAME: %foo)
+#[no_mangle]
+pub fn box_should_not_have_noalias_if_disabled(foo: Box<u8>) {
+    drop(foo);
+}
diff --git a/tests/codegen-llvm/noalias-box.rs b/tests/codegen-llvm/noalias-box.rs
new file mode 100644
index 00000000000..cccde775977
--- /dev/null
+++ b/tests/codegen-llvm/noalias-box.rs
@@ -0,0 +1,8 @@
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @box_should_have_noalias_by_default(
+// CHECK: noalias
+#[no_mangle]
+pub fn box_should_have_noalias_by_default(_b: Box<u8>) {}
diff --git a/tests/codegen-llvm/noalias-flag.rs b/tests/codegen-llvm/noalias-flag.rs
new file mode 100644
index 00000000000..67ba68ee6f8
--- /dev/null
+++ b/tests/codegen-llvm/noalias-flag.rs
@@ -0,0 +1,23 @@
+//@ compile-flags: -Copt-level=3 -Zmutable-noalias=no
+
+#![crate_type = "lib"]
+
+// `-Zmutable-noalias=no` should disable noalias on mut refs...
+
+// CHECK-LABEL: @test_mut_ref(
+// CHECK-NOT: noalias
+// CHECK-SAME: %x
+#[no_mangle]
+pub fn test_mut_ref(x: &mut i32) -> &mut i32 {
+    x
+}
+
+// ...but not on shared refs
+
+// CHECK-LABEL: @test_ref(
+// CHECK-SAME: noalias
+// CHECK-SAME: %x
+#[no_mangle]
+pub fn test_ref(x: &i32) -> &i32 {
+    x
+}
diff --git a/tests/codegen-llvm/noalias-freeze.rs b/tests/codegen-llvm/noalias-freeze.rs
new file mode 100644
index 00000000000..32c84014026
--- /dev/null
+++ b/tests/codegen-llvm/noalias-freeze.rs
@@ -0,0 +1,23 @@
+//@ compile-flags: -Copt-level=1
+
+// References returned by a Frozen pointer type
+// could be marked as "noalias", which caused miscompilation errors.
+// This test runs the most minimal possible code that can reproduce this bug,
+// and checks that noalias does not appear.
+// See https://github.com/rust-lang/rust/issues/46239
+
+#![crate_type = "lib"]
+
+fn project<T>(x: &(T,)) -> &T {
+    &x.0
+}
+
+fn dummy() {}
+
+// CHECK-LABEL: @foo(
+// CHECK-NOT: noalias
+#[no_mangle]
+pub fn foo() {
+    let f = (dummy as fn(),);
+    (*project(&f))();
+}
diff --git a/tests/codegen-llvm/noalias-refcell.rs b/tests/codegen-llvm/noalias-refcell.rs
new file mode 100644
index 00000000000..b37adf92b9c
--- /dev/null
+++ b/tests/codegen-llvm/noalias-refcell.rs
@@ -0,0 +1,14 @@
+//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes -Z mutable-noalias=yes
+
+#![crate_type = "lib"]
+
+use std::cell::{Ref, RefCell, RefMut};
+
+// Make sure that none of the arguments get a `noalias` attribute, because
+// the `RefCell` might alias writes after either `Ref`/`RefMut` is dropped.
+
+// CHECK-LABEL: @maybe_aliased(
+// CHECK-NOT: noalias
+// CHECK-SAME: %_refcell
+#[no_mangle]
+pub unsafe fn maybe_aliased(_: Ref<'_, i32>, _: RefMut<'_, i32>, _refcell: &RefCell<i32>) {}
diff --git a/tests/codegen-llvm/noalias-rwlockreadguard.rs b/tests/codegen-llvm/noalias-rwlockreadguard.rs
new file mode 100644
index 00000000000..c676dc32399
--- /dev/null
+++ b/tests/codegen-llvm/noalias-rwlockreadguard.rs
@@ -0,0 +1,14 @@
+//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes -Z mutable-noalias=yes
+
+#![crate_type = "lib"]
+
+use std::sync::{RwLock, RwLockReadGuard};
+
+// Make sure that `RwLockReadGuard` does not get a `noalias` attribute, because
+// the `RwLock` might alias writes after it is dropped.
+
+// CHECK-LABEL: @maybe_aliased(
+// CHECK-NOT: noalias
+// CHECK-SAME: %_data
+#[no_mangle]
+pub unsafe fn maybe_aliased(_: RwLockReadGuard<'_, i32>, _data: &RwLock<i32>) {}
diff --git a/tests/codegen-llvm/noalias-unpin.rs b/tests/codegen-llvm/noalias-unpin.rs
new file mode 100644
index 00000000000..30a8b399b97
--- /dev/null
+++ b/tests/codegen-llvm/noalias-unpin.rs
@@ -0,0 +1,15 @@
+//@ compile-flags: -Copt-level=3 -Z mutable-noalias=yes
+
+#![crate_type = "lib"]
+
+pub struct SelfRef {
+    self_ref: *mut SelfRef,
+    _pin: std::marker::PhantomPinned,
+}
+
+// CHECK-LABEL: @test_self_ref(
+// CHECK-NOT: noalias
+#[no_mangle]
+pub unsafe fn test_self_ref(s: &mut SelfRef) {
+    (*s.self_ref).self_ref = std::ptr::null_mut();
+}
diff --git a/tests/codegen-llvm/non-terminate/infinite-loop-1.rs b/tests/codegen-llvm/non-terminate/infinite-loop-1.rs
new file mode 100644
index 00000000000..9eab4939aee
--- /dev/null
+++ b/tests/codegen-llvm/non-terminate/infinite-loop-1.rs
@@ -0,0 +1,17 @@
+//@ compile-flags: -C opt-level=3
+
+#![crate_type = "lib"]
+
+fn infinite_loop() -> u8 {
+    loop {}
+}
+
+// CHECK-LABEL: @test
+#[no_mangle]
+fn test() -> u8 {
+    // CHECK-NOT: unreachable
+    // CHECK: br label %{{.+}}
+    // CHECK-NOT: unreachable
+    let x = infinite_loop();
+    x
+}
diff --git a/tests/codegen-llvm/non-terminate/infinite-loop-2.rs b/tests/codegen-llvm/non-terminate/infinite-loop-2.rs
new file mode 100644
index 00000000000..da29361cc96
--- /dev/null
+++ b/tests/codegen-llvm/non-terminate/infinite-loop-2.rs
@@ -0,0 +1,19 @@
+//@ compile-flags: -C opt-level=3
+
+#![crate_type = "lib"]
+
+fn infinite_loop() -> u8 {
+    let i = 2;
+    while i > 1 {}
+    1
+}
+
+// CHECK-LABEL: @test
+#[no_mangle]
+fn test() -> u8 {
+    // CHECK-NOT: unreachable
+    // CHECK: br label %{{.+}}
+    // CHECK-NOT: unreachable
+    let x = infinite_loop();
+    x
+}
diff --git a/tests/codegen-llvm/non-terminate/infinite-recursion.rs b/tests/codegen-llvm/non-terminate/infinite-recursion.rs
new file mode 100644
index 00000000000..19123639896
--- /dev/null
+++ b/tests/codegen-llvm/non-terminate/infinite-recursion.rs
@@ -0,0 +1,13 @@
+//@ compile-flags: -C opt-level=3
+
+#![crate_type = "lib"]
+#![allow(unconditional_recursion)]
+
+// CHECK-LABEL: @infinite_recursion
+#[no_mangle]
+fn infinite_recursion() -> u8 {
+    // CHECK-NOT: ret i8 undef
+    // CHECK: br label %{{.+}}
+    // CHECK-NOT: ret i8 undef
+    infinite_recursion()
+}
diff --git a/tests/codegen-llvm/non-terminate/nonempty-infinite-loop.rs b/tests/codegen-llvm/non-terminate/nonempty-infinite-loop.rs
new file mode 100644
index 00000000000..0db4ee61b1b
--- /dev/null
+++ b/tests/codegen-llvm/non-terminate/nonempty-infinite-loop.rs
@@ -0,0 +1,28 @@
+//@ compile-flags: -C opt-level=3
+
+#![crate_type = "lib"]
+
+// Verify that we don't miscompile this even if rustc didn't apply the trivial loop detection to
+// insert the sideeffect intrinsic.
+
+fn infinite_loop() -> u8 {
+    let mut x = 0;
+    // CHECK-NOT: sideeffect
+    loop {
+        if x == 42 {
+            x = 0;
+        } else {
+            x = 42;
+        }
+    }
+}
+
+// CHECK-LABEL: @test
+#[no_mangle]
+fn test() -> u8 {
+    // CHECK-NOT: unreachable
+    // CHECK: br label %{{.+}}
+    // CHECK-NOT: unreachable
+    let x = infinite_loop();
+    x
+}
diff --git a/tests/codegen-llvm/noreturn-uninhabited.rs b/tests/codegen-llvm/noreturn-uninhabited.rs
new file mode 100644
index 00000000000..a10795d3f3c
--- /dev/null
+++ b/tests/codegen-llvm/noreturn-uninhabited.rs
@@ -0,0 +1,31 @@
+//@ compile-flags: -g -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+#[derive(Clone, Copy)]
+pub enum EmptyEnum {}
+
+#[no_mangle]
+pub fn empty(x: &EmptyEnum) -> EmptyEnum {
+    // CHECK: @empty({{.*}}) unnamed_addr #0
+    // CHECK-NOT: ret void
+    // CHECK: call void @llvm.trap()
+    // CHECK: unreachable
+    *x
+}
+
+pub struct Foo(String, EmptyEnum);
+
+#[no_mangle]
+pub fn foo(x: String, y: &EmptyEnum) -> Foo {
+    // CHECK: @foo({{.*}}) unnamed_addr #0
+    // CHECK-NOT: ret %Foo
+    // CHECK: call void @llvm.trap()
+    // CHECK: unreachable
+    Foo(x, *y)
+}
+
+// CHECK: attributes #0 = {{{.*}} noreturn {{.*}}}
+
+// CHECK: DISubprogram(name: "empty", {{.*}} DIFlagNoReturn
+// CHECK: DISubprogram(name: "foo", {{.*}} DIFlagNoReturn
diff --git a/tests/codegen-llvm/noreturnflag.rs b/tests/codegen-llvm/noreturnflag.rs
new file mode 100644
index 00000000000..d9bb30b2703
--- /dev/null
+++ b/tests/codegen-llvm/noreturnflag.rs
@@ -0,0 +1,22 @@
+//@ compile-flags: -g -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+#[no_mangle]
+pub fn foo() -> ! {
+    // CHECK: @foo() unnamed_addr #0
+    loop {}
+}
+
+pub enum EmptyEnum {}
+
+#[no_mangle]
+pub fn bar() -> EmptyEnum {
+    // CHECK: @bar() unnamed_addr #0
+    loop {}
+}
+
+// CHECK: attributes #0 = {{{.*}} noreturn {{.*}}}
+
+// CHECK: DISubprogram(name: "foo", {{.*}} DIFlagNoReturn
+// CHECK: DISubprogram(name: "bar", {{.*}} DIFlagNoReturn
diff --git a/tests/codegen-llvm/nounwind.rs b/tests/codegen-llvm/nounwind.rs
new file mode 100644
index 00000000000..c910644458a
--- /dev/null
+++ b/tests/codegen-llvm/nounwind.rs
@@ -0,0 +1,15 @@
+//@ aux-build:nounwind.rs
+//@ compile-flags: -C no-prepopulate-passes -C panic=abort -C metadata=a
+//@ ignore-android
+
+#![crate_type = "lib"]
+
+extern crate nounwind;
+
+#[no_mangle]
+pub fn foo() {
+    nounwind::bar();
+    // CHECK: @foo() unnamed_addr #0
+    // CHECK: @bar() unnamed_addr #0
+    // CHECK: attributes #0 = { {{.*}}nounwind{{.*}} }
+}
diff --git a/tests/codegen-llvm/nrvo.rs b/tests/codegen-llvm/nrvo.rs
new file mode 100644
index 00000000000..7972186bfe5
--- /dev/null
+++ b/tests/codegen-llvm/nrvo.rs
@@ -0,0 +1,17 @@
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+
+// Ensure that we do not call `memcpy` for the following function.
+// `memset` and `init` should be called directly on the return pointer.
+#[no_mangle]
+pub fn nrvo(init: fn(&mut [u8; 4096])) -> [u8; 4096] {
+    // CHECK-LABEL: nrvo
+    // CHECK: @llvm.memset
+    // FIXME: turn on nrvo then check-not: @llvm.memcpy
+    // CHECK: ret
+    // CHECK-EMPTY
+    let mut buf = [0; 4096];
+    init(&mut buf);
+    buf
+}
diff --git a/tests/codegen-llvm/optimize-attr-1.rs b/tests/codegen-llvm/optimize-attr-1.rs
new file mode 100644
index 00000000000..db6bdcf9a8b
--- /dev/null
+++ b/tests/codegen-llvm/optimize-attr-1.rs
@@ -0,0 +1,59 @@
+//@ revisions: NO-OPT SIZE-OPT SPEED-OPT
+//@[NO-OPT] compile-flags: -Copt-level=0 -Ccodegen-units=1
+//@[SIZE-OPT] compile-flags: -Copt-level=s -Ccodegen-units=1
+//@[SPEED-OPT] compile-flags: -Copt-level=3 -Ccodegen-units=1
+
+#![feature(optimize_attribute)]
+#![crate_type = "rlib"]
+
+// CHECK-LABEL: define{{.*}}i32 @nothing
+// CHECK-SAME: [[NOTHING_ATTRS:#[0-9]+]]
+// SIZE-OPT: ret i32 4
+// SPEED-OPT: ret i32 4
+#[no_mangle]
+pub fn nothing() -> i32 {
+    2 + 2
+}
+
+// CHECK-LABEL: define{{.*}}i32 @size
+// CHECK-SAME: [[SIZE_ATTRS:#[0-9]+]]
+// SIZE-OPT: ret i32 6
+// SPEED-OPT: ret i32 6
+#[optimize(size)]
+#[no_mangle]
+pub fn size() -> i32 {
+    3 + 3
+}
+
+// CHECK-LABEL: define{{.*}}i32 @speed
+// NO-OPT-SAME: [[NOTHING_ATTRS]]
+// SPEED-OPT-SAME: [[NOTHING_ATTRS]]
+// SIZE-OPT-SAME: [[SPEED_ATTRS:#[0-9]+]]
+// SIZE-OPT: ret i32 8
+// SPEED-OPT: ret i32 8
+#[optimize(speed)]
+#[no_mangle]
+pub fn speed() -> i32 {
+    4 + 4
+}
+
+// CHECK-LABEL: define{{.*}}i32 @none
+// CHECK-SAME: [[NONE_ATTRS:#[0-9]+]]
+// SIZE-OPT: alloca
+// SPEED-OPT: alloca
+#[no_mangle]
+#[optimize(none)]
+pub fn none() -> i32 {
+    let arr = [0, 1, 2, 3, 4];
+    arr[4]
+}
+
+// NO-OPT-DAG: attributes [[SIZE_ATTRS]] = {{.*}}minsize{{.*}}optsize{{.*}}
+// SPEED-OPT-DAG: attributes [[SIZE_ATTRS]] = {{.*}}minsize{{.*}}optsize{{.*}}
+// SIZE-OPT-DAG: attributes [[NOTHING_ATTRS]] = {{.*}}optsize{{.*}}
+// SIZE-OPT-DAG: attributes [[SIZE_ATTRS]] = {{.*}}minsize{{.*}}optsize{{.*}}
+// CHECK-DAG: attributes [[NONE_ATTRS]] = {{.*}}noinline{{.*}}optnone{{.*}}
+
+// SIZE-OPT-DAG: attributes [[SPEED_ATTRS]]
+// SIZE-OPT-NOT: minsize
+// SIZE-OPT-NOT: optsize
diff --git a/tests/codegen-llvm/option-as-slice.rs b/tests/codegen-llvm/option-as-slice.rs
new file mode 100644
index 00000000000..39b34a2035b
--- /dev/null
+++ b/tests/codegen-llvm/option-as-slice.rs
@@ -0,0 +1,71 @@
+//@ compile-flags: -Copt-level=3 -Z randomize-layout=no
+//@ only-x86_64
+#![crate_type = "lib"]
+
+extern crate core;
+
+use core::num::NonZero;
+use core::option::Option;
+
+// CHECK-LABEL: @u64_opt_as_slice
+#[no_mangle]
+pub fn u64_opt_as_slice(o: &Option<u64>) -> &[u64] {
+    // CHECK-NOT: select
+    // CHECK-NOT: br
+    // CHECK-NOT: switch
+    // CHECK-NOT: icmp
+    // CHECK: %[[LEN:.+]] = load i64
+    // CHECK-SAME: !range ![[META_U64:[0-9]+]],
+    // CHECK-SAME: !noundef
+    // CHECK-NOT: select
+    // CHECK-NOT: br
+    // CHECK-NOT: switch
+    // CHECK-NOT: icmp
+    // CHECK: %[[T0:.+]] = insertvalue { ptr, i64 } poison, ptr %{{.+}}, 0
+    // CHECK-NEXT: %[[T1:.+]] = insertvalue { ptr, i64 } %[[T0]], i64 %[[LEN]], 1
+    // CHECK-NEXT: ret { ptr, i64 } %[[T1]]
+    o.as_slice()
+}
+
+// CHECK-LABEL: @nonzero_u64_opt_as_slice
+#[no_mangle]
+pub fn nonzero_u64_opt_as_slice(o: &Option<NonZero<u64>>) -> &[NonZero<u64>] {
+    // CHECK-NOT: select
+    // CHECK-NOT: br
+    // CHECK-NOT: switch
+    // CHECK-NOT: icmp
+    // CHECK: %[[NZ:.+]] = icmp ne i64 %{{.+}}, 0
+    // CHECK-NEXT: %[[LEN:.+]] = zext i1 %[[NZ]] to i64
+    // CHECK-NOT: select
+    // CHECK-NOT: br
+    // CHECK-NOT: switch
+    // CHECK-NOT: icmp
+    // CHECK: %[[T0:.+]] = insertvalue { ptr, i64 } poison, ptr %o, 0
+    // CHECK-NEXT: %[[T1:.+]] = insertvalue { ptr, i64 } %[[T0]], i64 %[[LEN]], 1
+    // CHECK-NEXT: ret { ptr, i64 } %[[T1]]
+    o.as_slice()
+}
+
+// CHECK-LABEL: @u8_opt_as_slice
+#[no_mangle]
+pub fn u8_opt_as_slice(o: &Option<u8>) -> &[u8] {
+    // CHECK-NOT: select
+    // CHECK-NOT: br
+    // CHECK-NOT: switch
+    // CHECK-NOT: icmp
+    // CHECK: %[[TAG:.+]] = load i8
+    // CHECK-SAME: !range ![[META_U8:[0-9]+]],
+    // CHECK-SAME: !noundef
+    // CHECK: %[[LEN:.+]] = zext{{.*}} i8 %[[TAG]] to i64
+    // CHECK-NOT: select
+    // CHECK-NOT: br
+    // CHECK-NOT: switch
+    // CHECK-NOT: icmp
+    // CHECK: %[[T0:.+]] = insertvalue { ptr, i64 } poison, ptr %{{.+}}, 0
+    // CHECK-NEXT: %[[T1:.+]] = insertvalue { ptr, i64 } %[[T0]], i64 %[[LEN]], 1
+    // CHECK-NEXT: ret { ptr, i64 } %[[T1]]
+    o.as_slice()
+}
+
+// CHECK: ![[META_U64]] = !{i64 0, i64 2}
+// CHECK: ![[META_U8]] = !{i8 0, i8 2}
diff --git a/tests/codegen-llvm/option-niche-eq.rs b/tests/codegen-llvm/option-niche-eq.rs
new file mode 100644
index 00000000000..3900cb79aa2
--- /dev/null
+++ b/tests/codegen-llvm/option-niche-eq.rs
@@ -0,0 +1,87 @@
+//@ revisions: REGULAR LLVM21
+//@ min-llvm-version: 20
+//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled
+//@ [LLVM21] min-llvm-version: 21
+#![crate_type = "lib"]
+
+extern crate core;
+use core::cmp::Ordering;
+use core::num::NonZero;
+use core::ptr::NonNull;
+
+// CHECK-LABEL: @non_zero_eq
+#[no_mangle]
+pub fn non_zero_eq(l: Option<NonZero<u32>>, r: Option<NonZero<u32>>) -> bool {
+    // CHECK: start:
+    // CHECK-NEXT: icmp eq i32
+    // CHECK-NEXT: ret i1
+    l == r
+}
+
+// CHECK-LABEL: @non_zero_signed_eq
+#[no_mangle]
+pub fn non_zero_signed_eq(l: Option<NonZero<i64>>, r: Option<NonZero<i64>>) -> bool {
+    // CHECK: start:
+    // CHECK-NEXT: icmp eq i64
+    // CHECK-NEXT: ret i1
+    l == r
+}
+
+// FIXME(#49892)
+// This currently relies on a manual implementation of `PartialOrd`/`Ord` for `Option`
+// Once LLVM is better able to optimize this pattern, we can return to using a derive.
+// CHECK-LABEL: @non_zero_ord
+#[no_mangle]
+pub fn non_zero_ord(a: Option<NonZero<u32>>, b: Option<NonZero<u32>>) -> bool {
+    // CHECK: start:
+    // CHECK-NEXT: icmp ult i32
+    // CHECK-NEXT: ret i1
+    a < b
+}
+
+// CHECK-LABEL: @non_null_eq
+#[no_mangle]
+pub fn non_null_eq(l: Option<NonNull<u8>>, r: Option<NonNull<u8>>) -> bool {
+    // CHECK: start:
+    // CHECK-NEXT: icmp eq ptr
+    // CHECK-NEXT: ret i1
+    l == r
+}
+
+// CHECK-LABEL: @ordering_eq
+#[no_mangle]
+pub fn ordering_eq(l: Option<Ordering>, r: Option<Ordering>) -> bool {
+    // CHECK: start:
+    // CHECK-NEXT: icmp eq i8
+    // CHECK-NEXT: ret i1
+    l == r
+}
+
+#[derive(PartialEq)]
+pub enum EnumWithNiche {
+    A,
+    B,
+    C,
+    D,
+    E,
+    F,
+    G,
+}
+
+// CHECK-LABEL: @niche_eq
+#[no_mangle]
+pub fn niche_eq(l: Option<EnumWithNiche>, r: Option<EnumWithNiche>) -> bool {
+    // CHECK: start:
+    // CHECK-NEXT: icmp eq i8
+    // CHECK-NEXT: ret i1
+    l == r
+}
+
+// LLVM21-LABEL: @bool_eq
+#[no_mangle]
+pub fn bool_eq(l: Option<bool>, r: Option<bool>) -> bool {
+    // LLVM21: start:
+    // LLVM21-NEXT: icmp eq i8
+    // LLVM21-NEXT: ret i1
+    l == r
+}
diff --git a/tests/codegen-llvm/option-niche-unfixed/option-nonzero-eq.rs b/tests/codegen-llvm/option-niche-unfixed/option-nonzero-eq.rs
new file mode 100644
index 00000000000..308856cfb7e
--- /dev/null
+++ b/tests/codegen-llvm/option-niche-unfixed/option-nonzero-eq.rs
@@ -0,0 +1,24 @@
+//@ should-fail
+//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled
+//! FIXME(#49892)
+//! Test that the derived implementation of `PartialEq` for `Option` is not fully
+//! optimized by LLVM. If this starts passing, the test and manual impl should
+//! be removed.
+#![crate_type = "lib"]
+
+use std::num::NonZero;
+
+#[derive(Copy, Clone, PartialEq, Eq)]
+pub enum Option<T> {
+    None,
+    Some(T),
+}
+
+// CHECK-LABEL: @non_zero_eq
+#[no_mangle]
+pub fn non_zero_eq(l: Option<NonZero<u32>>, r: Option<NonZero<u32>>) -> bool {
+    // CHECK: start:
+    // CHECK-NEXT: icmp eq i32
+    // CHECK-NEXT: ret i1
+    l == r
+}
diff --git a/tests/codegen-llvm/overaligned-constant.rs b/tests/codegen-llvm/overaligned-constant.rs
new file mode 100644
index 00000000000..0f5977880f2
--- /dev/null
+++ b/tests/codegen-llvm/overaligned-constant.rs
@@ -0,0 +1,35 @@
+// GVN may create indirect constants with higher alignment than their type requires. Verify that we
+// do not ICE during codegen, and that the LLVM constant has the higher alignment.
+//
+//@ compile-flags: -Zmir-opt-level=0 -Zmir-enable-passes=+GVN
+//@ compile-flags: -Cno-prepopulate-passes --crate-type=lib
+//@ only-64bit
+
+struct S(i32);
+
+struct SmallStruct(f32, Option<S>, &'static [f32]);
+
+// CHECK: [[const:@.*]] = private unnamed_addr constant
+// CHECK-SAME: , align 8
+
+#[no_mangle]
+pub fn overaligned_constant() {
+    // CHECK-LABEL: @overaligned_constant
+    // CHECK: [[full:%_.*]] = alloca [32 x i8], align 8
+    // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[full]], ptr align 8 [[const]], i64 32, i1 false)
+    let mut s = S(1);
+
+    s.0 = 3;
+
+    // SMALL_VAL corresponds to a MIR allocation with alignment 8.
+    const SMALL_VAL: SmallStruct = SmallStruct(4., Some(S(1)), &[]);
+
+    // In pre-codegen MIR:
+    // `a` is a scalar 4.
+    // `b` is an indirect constant at `SMALL_VAL`'s alloc with 0 offset.
+    // `c` is the empty slice.
+    //
+    // As a consequence, during codegen, we create a LLVM allocation for `SMALL_VAL`, with
+    // alignment 8, but only use the `Option<S>` field, at offset 0 with alignment 4.
+    let SmallStruct(a, b, c) = SMALL_VAL;
+}
diff --git a/tests/codegen-llvm/packed.rs b/tests/codegen-llvm/packed.rs
new file mode 100644
index 00000000000..6f62719282e
--- /dev/null
+++ b/tests/codegen-llvm/packed.rs
@@ -0,0 +1,153 @@
+//
+//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+#[repr(packed)]
+pub struct Packed1 {
+    dealign: u8,
+    data: u32,
+}
+
+#[repr(packed(2))]
+pub struct Packed2 {
+    dealign: u8,
+    data: u32,
+}
+
+// CHECK-LABEL: @write_pkd1
+#[no_mangle]
+pub fn write_pkd1(pkd: &mut Packed1) -> u32 {
+    // CHECK: %{{.*}} = load i32, ptr %{{.*}}, align 1
+    // CHECK: store i32 42, ptr %{{.*}}, align 1
+    let result = pkd.data;
+    pkd.data = 42;
+    result
+}
+
+// CHECK-LABEL: @write_pkd2
+#[no_mangle]
+pub fn write_pkd2(pkd: &mut Packed2) -> u32 {
+    // CHECK: %{{.*}} = load i32, ptr %{{.*}}, align 2
+    // CHECK: store i32 42, ptr %{{.*}}, align 2
+    let result = pkd.data;
+    pkd.data = 42;
+    result
+}
+
+pub struct Array([i32; 8]);
+#[repr(packed)]
+pub struct BigPacked1 {
+    dealign: u8,
+    data: Array,
+}
+
+#[repr(packed(2))]
+pub struct BigPacked2 {
+    dealign: u8,
+    data: Array,
+}
+
+// CHECK-LABEL: @call_pkd1
+#[no_mangle]
+pub fn call_pkd1(f: fn() -> Array) -> BigPacked1 {
+    // CHECK: [[ALLOCA:%[_a-z0-9]+]] = alloca [32 x i8]
+    // CHECK: call void %{{.*}}(ptr{{( captures(none))?}} noalias{{( nocapture)?}} noundef sret{{.*}} dereferenceable(32) [[ALLOCA]])
+    // CHECK: call void @llvm.memcpy.{{.*}}(ptr align 1 %{{.*}}, ptr align 4 %{{.*}}, i{{[0-9]+}} 32, i1 false)
+    // check that calls whose destination is a field of a packed struct
+    // go through an alloca rather than calling the function with an
+    // unaligned destination.
+    BigPacked1 { dealign: 0, data: f() }
+}
+
+// CHECK-LABEL: @call_pkd2
+#[no_mangle]
+pub fn call_pkd2(f: fn() -> Array) -> BigPacked2 {
+    // CHECK: [[ALLOCA:%[_a-z0-9]+]] = alloca [32 x i8]
+    // CHECK: call void %{{.*}}(ptr{{( captures(none))?}} noalias{{( nocapture)?}} noundef sret{{.*}} dereferenceable(32) [[ALLOCA]])
+    // CHECK: call void @llvm.memcpy.{{.*}}(ptr align 2 %{{.*}}, ptr align 4 %{{.*}}, i{{[0-9]+}} 32, i1 false)
+    // check that calls whose destination is a field of a packed struct
+    // go through an alloca rather than calling the function with an
+    // unaligned destination.
+    BigPacked2 { dealign: 0, data: f() }
+}
+
+// CHECK-LABEL: @write_packed_array1
+// CHECK: store i32 0, ptr %{{.+}}, align 1
+// CHECK: store i32 1, ptr %{{.+}}, align 1
+// CHECK: store i32 2, ptr %{{.+}}, align 1
+#[no_mangle]
+pub fn write_packed_array1(p: &mut BigPacked1) {
+    p.data.0[0] = 0;
+    p.data.0[1] = 1;
+    p.data.0[2] = 2;
+}
+
+// CHECK-LABEL: @write_packed_array2
+// CHECK: store i32 0, ptr %{{.+}}, align 2
+// CHECK: store i32 1, ptr %{{.+}}, align 2
+// CHECK: store i32 2, ptr %{{.+}}, align 2
+#[no_mangle]
+pub fn write_packed_array2(p: &mut BigPacked2) {
+    p.data.0[0] = 0;
+    p.data.0[1] = 1;
+    p.data.0[2] = 2;
+}
+
+// CHECK-LABEL: @repeat_packed_array1
+// CHECK: store i32 42, ptr %{{.+}}, align 1
+#[no_mangle]
+pub fn repeat_packed_array1(p: &mut BigPacked1) {
+    p.data.0 = [42; 8];
+}
+
+// CHECK-LABEL: @repeat_packed_array2
+// CHECK: store i32 42, ptr %{{.+}}, align 2
+#[no_mangle]
+pub fn repeat_packed_array2(p: &mut BigPacked2) {
+    p.data.0 = [42; 8];
+}
+
+#[repr(packed)]
+#[derive(Copy, Clone)]
+pub struct Packed1Pair(u8, u32);
+
+#[repr(packed(2))]
+#[derive(Copy, Clone)]
+pub struct Packed2Pair(u8, u32);
+
+// CHECK-LABEL: @pkd1_pair
+#[no_mangle]
+pub fn pkd1_pair(pair1: &mut Packed1Pair, pair2: &mut Packed1Pair) {
+    // CHECK: call void @llvm.memcpy.{{.*}}(ptr align 1 %{{.*}}, ptr align 1 %{{.*}}, i{{[0-9]+}} 5, i1 false)
+    *pair2 = *pair1;
+}
+
+// CHECK-LABEL: @pkd2_pair
+#[no_mangle]
+pub fn pkd2_pair(pair1: &mut Packed2Pair, pair2: &mut Packed2Pair) {
+    // CHECK: call void @llvm.memcpy.{{.*}}(ptr align 2 %{{.*}}, ptr align 2 %{{.*}}, i{{[0-9]+}} 6, i1 false)
+    *pair2 = *pair1;
+}
+
+#[repr(packed)]
+#[derive(Copy, Clone)]
+pub struct Packed1NestedPair((u32, u32));
+
+#[repr(packed(2))]
+#[derive(Copy, Clone)]
+pub struct Packed2NestedPair((u32, u32));
+
+// CHECK-LABEL: @pkd1_nested_pair
+#[no_mangle]
+pub fn pkd1_nested_pair(pair1: &mut Packed1NestedPair, pair2: &mut Packed1NestedPair) {
+    // CHECK: call void @llvm.memcpy.{{.*}}(ptr align 1 %{{.*}}, ptr align 1 %{{.*}}, i{{[0-9]+}} 8, i1 false)
+    *pair2 = *pair1;
+}
+
+// CHECK-LABEL: @pkd2_nested_pair
+#[no_mangle]
+pub fn pkd2_nested_pair(pair1: &mut Packed2NestedPair, pair2: &mut Packed2NestedPair) {
+    // CHECK: call void @llvm.memcpy.{{.*}}(ptr align 2 %{{.*}}, ptr align 2 %{{.*}}, i{{[0-9]+}} 8, i1 false)
+    *pair2 = *pair1;
+}
diff --git a/tests/codegen-llvm/panic-abort-windows.rs b/tests/codegen-llvm/panic-abort-windows.rs
new file mode 100644
index 00000000000..17fdd9cc726
--- /dev/null
+++ b/tests/codegen-llvm/panic-abort-windows.rs
@@ -0,0 +1,16 @@
+// This test is for *-windows only.
+//@ only-windows
+
+//@ compile-flags: -C no-prepopulate-passes -C panic=abort -Copt-level=3
+
+#![crate_type = "lib"]
+
+// CHECK: Function Attrs: nounwind uwtable
+// CHECK-NEXT: define void @normal_uwtable()
+#[no_mangle]
+pub fn normal_uwtable() {}
+
+// CHECK: Function Attrs: nounwind uwtable
+// CHECK-NEXT: define void @extern_uwtable()
+#[no_mangle]
+pub extern "C" fn extern_uwtable() {}
diff --git a/tests/codegen-llvm/panic-in-drop-abort.rs b/tests/codegen-llvm/panic-in-drop-abort.rs
new file mode 100644
index 00000000000..e89170e56ed
--- /dev/null
+++ b/tests/codegen-llvm/panic-in-drop-abort.rs
@@ -0,0 +1,57 @@
+//@ compile-flags: -Z panic-in-drop=abort -Copt-level=3
+//@ ignore-msvc
+
+// Ensure that unwinding code paths are eliminated from the output after
+// optimization.
+
+// This test uses ignore-msvc, because the expected optimization does not happen on targets using
+// SEH exceptions with the new LLVM pass manager anymore, see
+// https://github.com/llvm/llvm-project/issues/51311.
+
+// CHECK-NOT: {{(call|invoke).*}}should_not_appear_in_output
+
+#![crate_type = "lib"]
+use std::any::Any;
+use std::mem::forget;
+
+pub struct ExternDrop;
+impl Drop for ExternDrop {
+    #[inline(always)]
+    fn drop(&mut self) {
+        // This call may potentially unwind.
+        extern "Rust" {
+            fn extern_drop();
+        }
+        unsafe {
+            extern_drop();
+        }
+    }
+}
+
+struct AssertNeverDrop;
+impl Drop for AssertNeverDrop {
+    #[inline(always)]
+    fn drop(&mut self) {
+        // This call should be optimized away as unreachable.
+        extern "C" {
+            fn should_not_appear_in_output();
+        }
+        unsafe {
+            should_not_appear_in_output();
+        }
+    }
+}
+
+#[no_mangle]
+pub fn normal_drop(x: ExternDrop) {
+    let guard = AssertNeverDrop;
+    drop(x);
+    forget(guard);
+}
+
+#[no_mangle]
+pub fn indirect_drop(x: Box<dyn Any>) {
+    let guard = AssertNeverDrop;
+    drop(x);
+    forget(guard);
+}
diff --git a/tests/codegen-llvm/panic-unwind-default-uwtable.rs b/tests/codegen-llvm/panic-unwind-default-uwtable.rs
new file mode 100644
index 00000000000..06f616c519b
--- /dev/null
+++ b/tests/codegen-llvm/panic-unwind-default-uwtable.rs
@@ -0,0 +1,6 @@
+//@ compile-flags: -C panic=unwind -C no-prepopulate-passes -Copt-level=0
+
+#![crate_type = "lib"]
+
+// CHECK: attributes #{{.*}} uwtable
+pub fn foo() {}
diff --git a/tests/codegen-llvm/patchable-function-entry/patchable-function-entry-both-flags.rs b/tests/codegen-llvm/patchable-function-entry/patchable-function-entry-both-flags.rs
new file mode 100644
index 00000000000..72204c78a49
--- /dev/null
+++ b/tests/codegen-llvm/patchable-function-entry/patchable-function-entry-both-flags.rs
@@ -0,0 +1,64 @@
+//@ compile-flags: -Z patchable-function-entry=15,10
+
+#![feature(patchable_function_entry)]
+#![crate_type = "lib"]
+
+// This should have the default, as set by the compile flags
+#[no_mangle]
+pub fn fun0() {}
+
+// The attribute should override the compile flags
+#[no_mangle]
+#[patchable_function_entry(prefix_nops = 1, entry_nops = 2)]
+pub fn fun1() {}
+
+// If we override an attribute to 0 or unset, the attribute should go away
+#[no_mangle]
+#[patchable_function_entry(entry_nops = 0)]
+pub fn fun2() {}
+
+// The attribute should override the compile flags
+#[no_mangle]
+#[patchable_function_entry(prefix_nops = 20, entry_nops = 1)]
+pub fn fun3() {}
+
+// The attribute should override the compile flags
+#[no_mangle]
+#[patchable_function_entry(prefix_nops = 2, entry_nops = 19)]
+pub fn fun4() {}
+
+// The attribute should override patchable-function-entry to 3 and
+// patchable-function-prefix to the default of 0, clearing it entirely
+#[no_mangle]
+#[patchable_function_entry(entry_nops = 3)]
+pub fn fun5() {}
+
+// The attribute should override patchable-function-prefix to 4
+// and patchable-function-entry to the default of 0, clearing it entirely
+#[no_mangle]
+#[patchable_function_entry(prefix_nops = 4)]
+pub fn fun6() {}
+
+// CHECK: @fun0() unnamed_addr #0
+// CHECK: @fun1() unnamed_addr #1
+// CHECK: @fun2() unnamed_addr #2
+// CHECK: @fun3() unnamed_addr #3
+// CHECK: @fun4() unnamed_addr #4
+// CHECK: @fun5() unnamed_addr #5
+// CHECK: @fun6() unnamed_addr #6
+
+// CHECK: attributes #0 = { {{.*}}"patchable-function-entry"="5"{{.*}}"patchable-function-prefix"="10" {{.*}} }
+// CHECK: attributes #1 = { {{.*}}"patchable-function-entry"="2"{{.*}}"patchable-function-prefix"="1" {{.*}} }
+
+// CHECK-NOT: attributes #2 = { {{.*}}patchable-function-entry{{.*}} }
+// CHECK-NOT: attributes #2 = { {{.*}}patchable-function-prefix{{.*}} }
+// CHECK: attributes #2 = { {{.*}} }
+
+// CHECK: attributes #3 = { {{.*}}"patchable-function-entry"="1"{{.*}}"patchable-function-prefix"="20" {{.*}} }
+// CHECK: attributes #4 = { {{.*}}"patchable-function-entry"="19"{{.*}}"patchable-function-prefix"="2" {{.*}} }
+
+// CHECK: attributes #5 = { {{.*}}"patchable-function-entry"="3"{{.*}} }
+// CHECK-NOT: attributes #5 = { {{.*}}patchable-function-prefix{{.*}} }
+
+// CHECK: attributes #6 = { {{.*}}"patchable-function-prefix"="4"{{.*}} }
+// CHECK-NOT: attributes #6 = { {{.*}}patchable-function-entry{{.*}} }
diff --git a/tests/codegen-llvm/patchable-function-entry/patchable-function-entry-no-flag.rs b/tests/codegen-llvm/patchable-function-entry/patchable-function-entry-no-flag.rs
new file mode 100644
index 00000000000..3a7078fe551
--- /dev/null
+++ b/tests/codegen-llvm/patchable-function-entry/patchable-function-entry-no-flag.rs
@@ -0,0 +1,39 @@
+#![feature(patchable_function_entry)]
+#![crate_type = "lib"]
+
+// No patchable function entry should be set
+#[no_mangle]
+pub fn fun0() {}
+
+// The attribute should work even without compiler flags
+#[no_mangle]
+#[patchable_function_entry(prefix_nops = 1, entry_nops = 2)]
+pub fn fun1() {}
+
+// The attribute should work even without compiler flags
+// and only set patchable-function-entry to 3.
+#[no_mangle]
+#[patchable_function_entry(entry_nops = 3)]
+pub fn fun2() {}
+
+// The attribute should work even without compiler flags
+// and only set patchable-function-prefix to 4.
+#[no_mangle]
+#[patchable_function_entry(prefix_nops = 4)]
+pub fn fun3() {}
+
+// CHECK: @fun0() unnamed_addr #0
+// CHECK: @fun1() unnamed_addr #1
+// CHECK: @fun2() unnamed_addr #2
+// CHECK: @fun3() unnamed_addr #3
+
+// CHECK-NOT: attributes #0 = { {{.*}}patchable-function-entry{{.*}} }
+// CHECK-NOT: attributes #0 = { {{.*}}patchable-function-prefix{{.*}} }
+
+// CHECK: attributes #1 = { {{.*}}"patchable-function-entry"="2"{{.*}}"patchable-function-prefix"="1" {{.*}} }
+
+// CHECK: attributes #2 = { {{.*}}"patchable-function-entry"="3"{{.*}} }
+// CHECK-NOT: attributes #2 = { {{.*}}patchable-function-prefix{{.*}} }
+
+// CHECK: attributes #3 = { {{.*}}"patchable-function-prefix"="4"{{.*}} }
+// CHECK-NOT: attributes #3 = { {{.*}}patchable-function-entry{{.*}} }
diff --git a/tests/codegen-llvm/patchable-function-entry/patchable-function-entry-one-flag.rs b/tests/codegen-llvm/patchable-function-entry/patchable-function-entry-one-flag.rs
new file mode 100644
index 00000000000..8bdd61e461b
--- /dev/null
+++ b/tests/codegen-llvm/patchable-function-entry/patchable-function-entry-one-flag.rs
@@ -0,0 +1,66 @@
+//@ compile-flags: -Z patchable-function-entry=15
+
+#![feature(patchable_function_entry)]
+#![crate_type = "lib"]
+
+// This should have the default, as set by the compile flags
+#[no_mangle]
+pub fn fun0() {}
+
+// The attribute should override the compile flags
+#[no_mangle]
+#[patchable_function_entry(prefix_nops = 1, entry_nops = 2)]
+pub fn fun1() {}
+
+// If we override an attribute to 0 or unset, the attribute should go away
+#[no_mangle]
+#[patchable_function_entry(entry_nops = 0)]
+pub fn fun2() {}
+
+// The attribute should override the compile flags
+#[no_mangle]
+#[patchable_function_entry(prefix_nops = 20, entry_nops = 1)]
+pub fn fun3() {}
+
+// The attribute should override the compile flags
+#[no_mangle]
+#[patchable_function_entry(prefix_nops = 2, entry_nops = 19)]
+pub fn fun4() {}
+
+// The attribute should override patchable-function-entry to 3
+// and patchable-function-prefix to the default of 0, clearing it entirely
+#[no_mangle]
+#[patchable_function_entry(entry_nops = 3)]
+pub fn fun5() {}
+
+// The attribute should override patchable-function-prefix to 4
+// and patchable-function-entry to the default of 0, clearing it entirely
+#[no_mangle]
+#[patchable_function_entry(prefix_nops = 4)]
+pub fn fun6() {}
+
+// CHECK: @fun0() unnamed_addr #0
+// CHECK: @fun1() unnamed_addr #1
+// CHECK: @fun2() unnamed_addr #2
+// CHECK: @fun3() unnamed_addr #3
+// CHECK: @fun4() unnamed_addr #4
+// CHECK: @fun5() unnamed_addr #5
+// CHECK: @fun6() unnamed_addr #6
+
+// CHECK: attributes #0 = { {{.*}}"patchable-function-entry"="15" {{.*}} }
+// CHECK-NOT: attributes #0 = { {{.*}}patchable-function-prefix{{.*}} }
+
+// CHECK: attributes #1 = { {{.*}}"patchable-function-entry"="2"{{.*}}"patchable-function-prefix"="1" {{.*}} }
+
+// CHECK-NOT: attributes #2 = { {{.*}}patchable-function-entry{{.*}} }
+// CHECK-NOT: attributes #2 = { {{.*}}patchable-function-prefix{{.*}} }
+// CHECK: attributes #2 = { {{.*}} }
+
+// CHECK: attributes #3 = { {{.*}}"patchable-function-entry"="1"{{.*}}"patchable-function-prefix"="20" {{.*}} }
+// CHECK: attributes #4 = { {{.*}}"patchable-function-entry"="19"{{.*}}"patchable-function-prefix"="2" {{.*}} }
+
+// CHECK: attributes #5 = { {{.*}}"patchable-function-entry"="3"{{.*}} }
+// CHECK-NOT: attributes #5 = { {{.*}}patchable-function-prefix{{.*}} }
+
+// CHECK: attributes #6 = { {{.*}}"patchable-function-prefix"="4"{{.*}} }
+// CHECK-NOT: attributes #6 = { {{.*}}patchable-function-entry{{.*}} }
diff --git a/tests/codegen-llvm/pattern_type_symbols.rs b/tests/codegen-llvm/pattern_type_symbols.rs
new file mode 100644
index 00000000000..e86a9ef27de
--- /dev/null
+++ b/tests/codegen-llvm/pattern_type_symbols.rs
@@ -0,0 +1,22 @@
+//! Check that symbol names with pattern types in them are
+//! different from the same symbol with the base type
+
+//@ compile-flags: -Csymbol-mangling-version=v0 -Copt-level=0 --crate-type=lib
+
+#![feature(pattern_types)]
+#![feature(pattern_type_macro)]
+
+use std::pat::pattern_type;
+
+type NanoU32 = crate::pattern_type!(u32 is 0..=999_999_999);
+
+fn foo<T>() {}
+
+pub fn bar() {
+    // CHECK: call pattern_type_symbols::foo::<u32>
+    // CHECK: call void @_RINvC[[CRATE_IDENT:[a-zA-Z0-9]{12}]]_20pattern_type_symbols3foomEB2_
+    foo::<u32>();
+    // CHECK: call pattern_type_symbols::foo::<(u32, [(); 0], [(); 999999999])>
+    // CHECK: call void @_RINvC[[CRATE_IDENT]]_20pattern_type_symbols3fooTmAum0_Aum3b9ac9ff_EEB2_
+    foo::<NanoU32>();
+}
diff --git a/tests/codegen-llvm/personality_lifetimes.rs b/tests/codegen-llvm/personality_lifetimes.rs
new file mode 100644
index 00000000000..cd81db63953
--- /dev/null
+++ b/tests/codegen-llvm/personality_lifetimes.rs
@@ -0,0 +1,32 @@
+//@ ignore-msvc
+//@ needs-unwind
+
+//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+struct S;
+
+impl Drop for S {
+    #[inline(never)]
+    fn drop(&mut self) {}
+}
+
+#[inline(never)]
+fn might_unwind() {}
+
+// CHECK-LABEL: @test
+#[no_mangle]
+pub fn test() {
+    let _s = S;
+    // Check that the personality slot alloca gets a lifetime start in each cleanup block, not just
+    // in the first one.
+    // CHECK: [[SLOT:%[0-9]+]] = alloca [{{[0-9]+}} x i8]
+    // CHECK-LABEL: cleanup:
+    // CHECK: call void @llvm.lifetime.start.{{.*}}({{.*}})
+    // CHECK-LABEL: cleanup1:
+    // CHECK: call void @llvm.lifetime.start.{{.*}}({{.*}})
+    might_unwind();
+    let _t = S;
+    might_unwind();
+}
diff --git a/tests/codegen-llvm/pgo-counter-bias.rs b/tests/codegen-llvm/pgo-counter-bias.rs
new file mode 100644
index 00000000000..48e815dda04
--- /dev/null
+++ b/tests/codegen-llvm/pgo-counter-bias.rs
@@ -0,0 +1,10 @@
+// Test that __llvm_profile_counter_bias does not get internalized by lto.
+
+//@ ignore-apple -runtime-counter-relocation not honored on Mach-O
+//@ compile-flags: -Cprofile-generate -Cllvm-args=-runtime-counter-relocation -Clto=fat
+//@ compile-flags: -Zno-profiler-runtime
+//@ no-prefer-dynamic
+
+// CHECK: @__llvm_profile_counter_bias = {{.*}}global
+
+pub fn main() {}
diff --git a/tests/codegen-llvm/pgo-instrumentation.rs b/tests/codegen-llvm/pgo-instrumentation.rs
new file mode 100644
index 00000000000..a8f12ccce1c
--- /dev/null
+++ b/tests/codegen-llvm/pgo-instrumentation.rs
@@ -0,0 +1,20 @@
+// Test that `-Cprofile-generate` creates expected instrumentation artifacts in LLVM IR.
+
+//@ compile-flags: -Zno-profiler-runtime
+//@ compile-flags: -Cprofile-generate -Ccodegen-units=1
+
+// CHECK: @__llvm_profile_raw_version =
+// CHECK-DAG: @__profc_{{.*}}pgo_instrumentation{{.*}}some_function{{.*}} = {{.*}}global
+// CHECK-DAG: @__profd_{{.*}}pgo_instrumentation{{.*}}some_function{{.*}} = {{.*}}global
+// CHECK-DAG: @__profc_{{.*}}pgo_instrumentation{{.*}}some_other_function{{.*}} = {{.*}}global
+// CHECK-DAG: @__profd_{{.*}}pgo_instrumentation{{.*}}some_other_function{{.*}} = {{.*}}global
+// CHECK: @__llvm_profile_filename = {{.*}}"default_%m.profraw\00"{{.*}}
+
+#![crate_type = "lib"]
+
+#[inline(never)]
+fn some_function() {}
+
+pub fn some_other_function() {
+    some_function();
+}
diff --git a/tests/codegen-llvm/pic-relocation-model.rs b/tests/codegen-llvm/pic-relocation-model.rs
new file mode 100644
index 00000000000..a1d1678a6bd
--- /dev/null
+++ b/tests/codegen-llvm/pic-relocation-model.rs
@@ -0,0 +1,19 @@
+//@ compile-flags: -C relocation-model=pic -Copt-level=0
+
+#![crate_type = "rlib"]
+
+// CHECK: define i8 @call_foreign_fn()
+#[no_mangle]
+pub fn call_foreign_fn() -> u8 {
+    unsafe { foreign_fn() }
+}
+
+// (Allow but do not require `zeroext` here, because it is not worth effort to
+// spell out which targets have it and which ones do not; see rust#97800.)
+
+// CHECK: declare{{( zeroext)?}} i8 @foreign_fn()
+extern "C" {
+    fn foreign_fn() -> u8;
+}
+
+// CHECK: !{i32 {{[78]}}, !"PIC Level", i32 2}
diff --git a/tests/codegen-llvm/pie-relocation-model.rs b/tests/codegen-llvm/pie-relocation-model.rs
new file mode 100644
index 00000000000..cb8de91ccd7
--- /dev/null
+++ b/tests/codegen-llvm/pie-relocation-model.rs
@@ -0,0 +1,22 @@
+//@ compile-flags: -C relocation-model=pie -Copt-level=0
+//@ only-x86_64-unknown-linux-gnu
+
+#![crate_type = "rlib"]
+
+// With PIE we know local functions cannot be interpositioned, we can mark them
+// as dso_local.
+// CHECK: define dso_local i8 @call_foreign_fn()
+#[no_mangle]
+pub fn call_foreign_fn() -> u8 {
+    unsafe { foreign_fn() }
+}
+
+// External functions are still marked as non-dso_local, since we don't know if the symbol
+// is defined in the binary or in the shared library.
+// CHECK: declare i8 @foreign_fn()
+extern "C" {
+    fn foreign_fn() -> u8;
+}
+
+// CHECK: !{i32 {{[78]}}, !"PIC Level", i32 2}
+// CHECK: !{i32 7, !"PIE Level", i32 2}
diff --git a/tests/codegen-llvm/placement-new.rs b/tests/codegen-llvm/placement-new.rs
new file mode 100644
index 00000000000..7f7f0033bec
--- /dev/null
+++ b/tests/codegen-llvm/placement-new.rs
@@ -0,0 +1,39 @@
+//@ compile-flags: -Copt-level=3
+//@ compile-flags: -Zmerge-functions=disabled
+#![crate_type = "lib"]
+
+// Test to check that types with "complex" destructors, but trivial `Default` impls
+// are constructed directly into the allocation in `Box::default` and `Arc::default`.
+
+use std::rc::Rc;
+use std::sync::Arc;
+
+// CHECK-LABEL: @box_default_inplace
+#[no_mangle]
+pub fn box_default_inplace() -> Box<(String, String)> {
+    // CHECK-NOT: alloca
+    // CHECK: [[BOX:%.*]] = {{.*}}call {{.*}}__rust_alloc(
+    // CHECK-NOT: call void @llvm.memcpy
+    // CHECK: ret ptr [[BOX]]
+    Box::default()
+}
+
+// CHECK-LABEL: @rc_default_inplace
+#[no_mangle]
+pub fn rc_default_inplace() -> Rc<(String, String)> {
+    // CHECK-NOT: alloca
+    // CHECK: [[RC:%.*]] = {{.*}}call {{.*}}__rust_alloc(
+    // CHECK-NOT: call void @llvm.memcpy
+    // CHECK: ret ptr [[RC]]
+    Rc::default()
+}
+
+// CHECK-LABEL: @arc_default_inplace
+#[no_mangle]
+pub fn arc_default_inplace() -> Arc<(String, String)> {
+    // CHECK-NOT: alloca
+    // CHECK: [[ARC:%.*]] = {{.*}}call {{.*}}__rust_alloc(
+    // CHECK-NOT: call void @llvm.memcpy
+    // CHECK: ret ptr [[ARC]]
+    Arc::default()
+}
diff --git a/tests/codegen-llvm/powerpc64le-struct-align-128.rs b/tests/codegen-llvm/powerpc64le-struct-align-128.rs
new file mode 100644
index 00000000000..c1c1ac26485
--- /dev/null
+++ b/tests/codegen-llvm/powerpc64le-struct-align-128.rs
@@ -0,0 +1,96 @@
+// Test that structs aligned to 128 bits are passed with the correct ABI on powerpc64le.
+// This is similar to aarch64-struct-align-128.rs, but for ppc.
+
+//@ add-core-stubs
+//@ compile-flags: --target powerpc64le-unknown-linux-gnu
+//@ needs-llvm-components: powerpc
+
+#![feature(no_core, lang_items)]
+#![crate_type = "lib"]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+#[repr(C)]
+pub struct Align8 {
+    pub a: u64,
+    pub b: u64,
+}
+
+#[repr(transparent)]
+pub struct Transparent8 {
+    a: Align8,
+}
+
+#[repr(C)]
+pub struct Wrapped8 {
+    a: Align8,
+}
+
+extern "C" {
+    // CHECK: declare void @test_8([2 x i64], [2 x i64], [2 x i64])
+    fn test_8(a: Align8, b: Transparent8, c: Wrapped8);
+}
+
+#[repr(C)]
+#[repr(align(16))]
+pub struct Align16 {
+    pub a: u64,
+    pub b: u64,
+}
+
+#[repr(transparent)]
+pub struct Transparent16 {
+    a: Align16,
+}
+
+#[repr(C)]
+pub struct Wrapped16 {
+    pub a: Align16,
+}
+
+extern "C" {
+    // It's important that this produces [1 x i128]  rather than just i128!
+    // CHECK: declare void @test_16([1 x i128], [1 x i128], [1 x i128])
+    fn test_16(a: Align16, b: Transparent16, c: Wrapped16);
+}
+
+#[repr(C)]
+#[repr(align(32))]
+pub struct Align32 {
+    pub a: u64,
+    pub b: u64,
+    pub c: u64,
+}
+
+#[repr(transparent)]
+pub struct Transparent32 {
+    a: Align32,
+}
+
+#[repr(C)]
+pub struct Wrapped32 {
+    pub a: Align32,
+}
+
+extern "C" {
+    // CHECK: declare void @test_32([2 x i128], [2 x i128], [2 x i128])
+    fn test_32(a: Align32, b: Transparent32, c: Wrapped32);
+}
+
+pub unsafe fn main(
+    a1: Align8,
+    a2: Transparent8,
+    a3: Wrapped8,
+    b1: Align16,
+    b2: Transparent16,
+    b3: Wrapped16,
+    c1: Align32,
+    c2: Transparent32,
+    c3: Wrapped32,
+) {
+    test_8(a1, a2, a3);
+    test_16(b1, b2, b3);
+    test_32(c1, c2, c3);
+}
diff --git a/tests/codegen-llvm/precondition-checks.rs b/tests/codegen-llvm/precondition-checks.rs
new file mode 100644
index 00000000000..16812ca1720
--- /dev/null
+++ b/tests/codegen-llvm/precondition-checks.rs
@@ -0,0 +1,25 @@
+//@ compile-flags: -Cno-prepopulate-passes -Copt-level=0 -Cdebug-assertions=no
+
+// This test ensures that in a debug build which turns off debug assertions, we do not monomorphize
+// any of the standard library's unsafe precondition checks.
+// The naive codegen of those checks contains the actual check underneath an `if false`, which
+// could be optimized out if optimizations are enabled. But if we rely on optimizations to remove
+// panic branches, then we can't link compiler_builtins without optimizing it, which means that
+// -Zbuild-std doesn't work with -Copt-level=0.
+//
+// In other words, this tests for a mandatory optimization.
+
+#![crate_type = "lib"]
+
+use std::ptr::NonNull;
+
+// CHECK-LABEL: ; core::ptr::non_null::NonNull<T>::new_unchecked
+// CHECK-NOT: call
+// CHECK: }
+
+// CHECK-LABEL: @nonnull_new
+#[no_mangle]
+pub unsafe fn nonnull_new(ptr: *mut u8) -> NonNull<u8> {
+    // CHECK: ; call core::ptr::non_null::NonNull<T>::new_unchecked
+    unsafe { NonNull::new_unchecked(ptr) }
+}
diff --git a/tests/codegen-llvm/ptr-arithmetic.rs b/tests/codegen-llvm/ptr-arithmetic.rs
new file mode 100644
index 00000000000..fc4441ef448
--- /dev/null
+++ b/tests/codegen-llvm/ptr-arithmetic.rs
@@ -0,0 +1,33 @@
+//@ compile-flags: -Copt-level=3 -Z merge-functions=disabled
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: ptr @i32_add(
+// CHECK-SAME: [[WORD:i[0-9]+]] noundef %n)
+#[no_mangle]
+pub unsafe fn i32_add(p: *const i32, n: usize) -> *const i32 {
+    // CHECK: %[[TEMP:.+]] = getelementptr inbounds{{( nuw)?}} i32, ptr %p, [[WORD]] %n
+    // CHECK: ret ptr %[[TEMP]]
+    p.add(n)
+}
+
+// Ensure we tell LLVM that the negation in `sub` can't overflow.
+
+// CHECK-LABEL: ptr @i32_sub(
+// CHECK-SAME: [[WORD:i[0-9]+]] noundef %n)
+#[no_mangle]
+pub unsafe fn i32_sub(p: *const i32, n: usize) -> *const i32 {
+    // CHECK: %[[DELTA:.+]] = sub nsw [[WORD]] 0, %n
+    // CHECK: %[[TEMP:.+]] = getelementptr inbounds i32, ptr %p, [[WORD]] %[[DELTA]]
+    // CHECK: ret ptr %[[TEMP]]
+    p.sub(n)
+}
+
+// CHECK-LABEL: ptr @i32_offset(
+// CHECK-SAME: [[WORD:i[0-9]+]] noundef %d)
+#[no_mangle]
+pub unsafe fn i32_offset(p: *const i32, d: isize) -> *const i32 {
+    // CHECK: %[[TEMP:.+]] = getelementptr inbounds i32, ptr %p, [[WORD]] %d
+    // CHECK: ret ptr %[[TEMP]]
+    p.offset(d)
+}
diff --git a/tests/codegen-llvm/ptr-read-metadata.rs b/tests/codegen-llvm/ptr-read-metadata.rs
new file mode 100644
index 00000000000..b38cfdbff88
--- /dev/null
+++ b/tests/codegen-llvm/ptr-read-metadata.rs
@@ -0,0 +1,94 @@
+//@ compile-flags: -Copt-level=3 -Z merge-functions=disabled
+
+#![crate_type = "lib"]
+
+// Ensure that various forms of reading pointers correctly annotate the `load`s
+// with `!noundef` and `!range` metadata to enable extra optimization.
+
+use std::mem::MaybeUninit;
+
+// CHECK-LABEL: define {{(dso_local )?}}noundef i8 @copy_byte(
+#[no_mangle]
+pub unsafe fn copy_byte(p: *const u8) -> u8 {
+    // CHECK-NOT: load
+    // CHECK: load i8, ptr %p, align 1
+    // CHECK-SAME: !noundef !
+    // CHECK-NOT: load
+    *p
+}
+
+// CHECK-LABEL: define {{(dso_local )?}}noundef i8 @read_byte(
+#[no_mangle]
+pub unsafe fn read_byte(p: *const u8) -> u8 {
+    // CHECK-NOT: load
+    // CHECK: load i8, ptr %p, align 1
+    // CHECK-SAME: !noundef !
+    // CHECK-NOT: load
+    p.read()
+}
+
+// CHECK-LABEL: define {{(dso_local )?}}i8 @read_byte_maybe_uninit(
+#[no_mangle]
+pub unsafe fn read_byte_maybe_uninit(p: *const MaybeUninit<u8>) -> MaybeUninit<u8> {
+    // CHECK-NOT: load
+    // CHECK: load i8, ptr %p, align 1
+    // CHECK-NOT: noundef
+    // CHECK-NOT: load
+    p.read()
+}
+
+// CHECK-LABEL: define {{(dso_local )?}}noundef i8 @read_byte_assume_init(
+#[no_mangle]
+pub unsafe fn read_byte_assume_init(p: &MaybeUninit<u8>) -> u8 {
+    // CHECK-NOT: load
+    // CHECK: load i8, ptr %p, align 1
+    // CHECK-SAME: !noundef !
+    // CHECK-NOT: load
+    p.assume_init_read()
+}
+
+// CHECK-LABEL: define {{(dso_local )?}}noundef {{(range\(.*\) )?}}i32 @copy_char(
+#[no_mangle]
+pub unsafe fn copy_char(p: *const char) -> char {
+    // CHECK-NOT: load
+    // CHECK: load i32, ptr %p
+    // CHECK-SAME: !range ![[RANGE:[0-9]+]]
+    // CHECK-SAME: !noundef !
+    // CHECK-NOT: load
+    *p
+}
+
+// CHECK-LABEL: define {{(dso_local )?}}noundef {{(range\(.*\) )?}}i32 @read_char(
+#[no_mangle]
+pub unsafe fn read_char(p: *const char) -> char {
+    // CHECK-NOT: load
+    // CHECK: load i32, ptr %p
+    // CHECK-SAME: !range ![[RANGE]]
+    // CHECK-SAME: !noundef !
+    // CHECK-NOT: load
+    p.read()
+}
+
+// CHECK-LABEL: define {{(dso_local )?}}i32 @read_char_maybe_uninit(
+#[no_mangle]
+pub unsafe fn read_char_maybe_uninit(p: *const MaybeUninit<char>) -> MaybeUninit<char> {
+    // CHECK-NOT: load
+    // CHECK: load i32, ptr %p
+    // CHECK-NOT: range
+    // CHECK-NOT: noundef
+    // CHECK-NOT: load
+    p.read()
+}
+
+// CHECK-LABEL: define {{(dso_local )?}}noundef {{(range\(.*\) )?}}i32 @read_char_assume_init(
+#[no_mangle]
+pub unsafe fn read_char_assume_init(p: &MaybeUninit<char>) -> char {
+    // CHECK-NOT: load
+    // CHECK: load i32, ptr %p
+    // CHECK-SAME: !range ![[RANGE]]
+    // CHECK-SAME: !noundef !
+    // CHECK-NOT: load
+    p.assume_init_read()
+}
+
+// CHECK: ![[RANGE]] = !{i32 0, i32 1114112}
diff --git a/tests/codegen-llvm/range-attribute.rs b/tests/codegen-llvm/range-attribute.rs
new file mode 100644
index 00000000000..b81ff9ab3e2
--- /dev/null
+++ b/tests/codegen-llvm/range-attribute.rs
@@ -0,0 +1,74 @@
+// Checks that range metadata gets emitted on functions result and arguments
+// with scalar value.
+
+// 32-bit systems will return 128bit values using a return area pointer.
+//@ revisions: bit32 bit64
+//@[bit32] only-32bit
+//@[bit64] only-64bit
+//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+use std::num::NonZero;
+
+// Hack to get the correct size for usize
+// CHECK: @helper([[USIZE:i[0-9]+]] noundef %_1)
+#[no_mangle]
+pub fn helper(_: usize) {}
+
+// bit32: void @nonzero_int({{.*}} sret([16 x i8]) {{.*}}, i128 noundef range(i128 1, 0) %x)
+// bit64: noundef range(i128 1, 0) i128 @nonzero_int(i128 noundef range(i128 1, 0) %x)
+#[no_mangle]
+pub fn nonzero_int(x: NonZero<u128>) -> NonZero<u128> {
+    x
+}
+
+// CHECK: noundef range(i8 0, 3) i8 @optional_bool(i8{{.*}} range(i8 0, 3) %x)
+#[no_mangle]
+pub fn optional_bool(x: Option<bool>) -> Option<bool> {
+    x
+}
+
+pub enum Enum0 {
+    A(bool),
+    B,
+    C,
+}
+
+// CHECK: noundef range(i8 0, 4) i8 @enum0_value(i8{{.*}} range(i8 0, 4) %x)
+#[no_mangle]
+pub fn enum0_value(x: Enum0) -> Enum0 {
+    x
+}
+
+pub enum Enum1 {
+    A(u64),
+    B(u64),
+    C(u64),
+}
+
+// bit32: void @enum1_value({{.*}} sret({{[^,]*}}) {{[^,]*}}, [[ENUM1_TYP:i[0-9]+]]
+// bit64: { [[ENUM1_TYP:i[0-9]+]], i64 } @enum1_value([[ENUM1_TYP]]
+// CHECK-SAME: noundef range([[ENUM1_TYP]] 0, 3) %x.0, i64 noundef %x.1)
+#[no_mangle]
+pub fn enum1_value(x: Enum1) -> Enum1 {
+    x
+}
+
+pub enum Enum2 {
+    A(Enum0),
+    B(Enum0),
+    C(Enum0),
+}
+
+// CHECK: { i8, i8 } @enum2_value(i8 noundef range(i8 0, 3) %x.0, i8 noundef %x.1)
+#[no_mangle]
+pub fn enum2_value(x: Enum2) -> Enum2 {
+    x
+}
+
+// CHECK: noundef [[USIZE]] @takes_slice(ptr noalias noundef nonnull readonly align 4 %x.0, [[USIZE]] noundef %x.1)
+#[no_mangle]
+pub fn takes_slice(x: &[i32]) -> usize {
+    x.len()
+}
diff --git a/tests/codegen-llvm/range-loop.rs b/tests/codegen-llvm/range-loop.rs
new file mode 100644
index 00000000000..b131beb40dd
--- /dev/null
+++ b/tests/codegen-llvm/range-loop.rs
@@ -0,0 +1,44 @@
+//@ ignore-std-debug-assertions
+//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+// Ensure that MIR optimizations have cleaned things up enough that the IR we
+// emit is good even without running the LLVM optimizations.
+
+// CHECK-NOT: define
+
+// CHECK-LABEL: define{{.+}}void @call_for_zero_to_n
+#[no_mangle]
+pub fn call_for_zero_to_n(n: u32, f: fn(u32)) {
+    // CHECK: start:
+    // CHECK-NOT: alloca
+    // CHECK: %[[IND:.+]] = alloca [4 x i8]
+    // CHECK-NEXT: %[[ALWAYS_SOME_OPTION:.+]] = alloca
+    // CHECK-NOT: alloca
+    // CHECK: store i32 0, ptr %[[IND]],
+    // CHECK: br label %[[HEAD:.+]]
+
+    // CHECK: [[HEAD]]:
+    // CHECK: %[[T1:.+]] = load i32, ptr %[[IND]],
+    // CHECK: %[[NOT_DONE:.+]] = icmp ult i32 %[[T1]], %n
+    // CHECK: br i1 %[[NOT_DONE]], label %[[BODY:.+]], label %[[BREAK:.+]]
+
+    // CHECK: [[BREAK]]:
+    // CHECK: ret void
+
+    // CHECK: [[BODY]]:
+    // CHECK: %[[T2:.+]] = load i32, ptr %[[IND]],
+    // CHECK: %[[T3:.+]] = add nuw i32 %[[T2]], 1
+    // CHECK: store i32 %[[T3]], ptr %[[IND]],
+
+    // CHECK: store i32 %[[T2]]
+    // CHECK: %[[T4:.+]] = load i32
+    // CHECK: call void %f(i32{{.+}}%[[T4]])
+
+    for i in 0..n {
+        f(i);
+    }
+}
+
+// CHECK-NOT: define
diff --git a/tests/codegen-llvm/range_to_inclusive.rs b/tests/codegen-llvm/range_to_inclusive.rs
new file mode 100644
index 00000000000..6d939f40f55
--- /dev/null
+++ b/tests/codegen-llvm/range_to_inclusive.rs
@@ -0,0 +1,28 @@
+//! Test that `RangeTo` and `RangeToInclusive` generate identical
+//! (and optimal) code; #63646
+//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled
+#![crate_type = "lib"]
+
+#[no_mangle]
+// CHECK-LABEL: range_to(
+pub fn range_to(a: i32, mut b: i32) -> i32 {
+    // CHECK: %1 = and i32 %0, %a
+    // CHECK-NEXT: ret i32 %1
+    for _ in 0..65 {
+        b &= a;
+    }
+
+    b
+}
+
+#[no_mangle]
+// CHECK-LABEL: range_to_inclusive(
+pub fn range_to_inclusive(a: i32, mut b: i32) -> i32 {
+    // CHECK: %1 = and i32 %0, %a
+    // CHECK-NEXT: ret i32 %1
+    for _ in 0..=64 {
+        b &= a;
+    }
+
+    b
+}
diff --git a/tests/codegen-llvm/refs.rs b/tests/codegen-llvm/refs.rs
new file mode 100644
index 00000000000..97c36295085
--- /dev/null
+++ b/tests/codegen-llvm/refs.rs
@@ -0,0 +1,21 @@
+//@ compile-flags: -C no-prepopulate-passes -Zmir-opt-level=0 -Copt-level=0
+
+#![crate_type = "lib"]
+
+// Hack to get the correct size for the length part in slices
+// CHECK: @helper([[USIZE:i[0-9]+]] %_1)
+#[no_mangle]
+pub fn helper(_: usize) {}
+
+// CHECK-LABEL: @ref_dst
+#[no_mangle]
+pub fn ref_dst(s: &[u8]) {
+    // We used to generate an extra alloca and memcpy to ref the dst, so check that we copy
+    // directly to the alloca for "x"
+    // CHECK: store ptr %s.0, {{.*}} %x
+    // CHECK: [[X1:%[0-9]+]] = getelementptr inbounds i8, {{.*}} %x, {{i32 4|i64 8}}
+    // CHECK: store [[USIZE]] %s.1, {{.*}} [[X1]]
+
+    let x = &*s;
+    &x; // keep variable in an alloca
+}
diff --git a/tests/codegen-llvm/reg-struct-return.rs b/tests/codegen-llvm/reg-struct-return.rs
new file mode 100644
index 00000000000..dfc9f8c519c
--- /dev/null
+++ b/tests/codegen-llvm/reg-struct-return.rs
@@ -0,0 +1,206 @@
+// Checks how `reg-struct-return` flag works with different calling conventions:
+// Return struct with 8/16/32/64 bit size will be converted into i8/i16/i32/i64
+// (like abi_return_struct_as_int target spec).
+// x86 only.
+
+//@ revisions: ENABLED DISABLED
+//@ add-core-stubs
+//@ compile-flags: --target i686-unknown-linux-gnu -Cno-prepopulate-passes -Copt-level=3
+//@ [ENABLED] compile-flags: -Zreg-struct-return
+//@ needs-llvm-components: x86
+
+#![crate_type = "lib"]
+#![no_std]
+#![no_core]
+#![feature(no_core, lang_items)]
+
+extern crate minicore;
+use minicore::*;
+
+#[repr(C)]
+pub struct Foo {
+    x: u32,
+    y: u32,
+}
+
+#[repr(C)]
+pub struct Foo1 {
+    x: u32,
+}
+
+#[repr(C)]
+pub struct Foo2 {
+    x: bool,
+    y: bool,
+    z: i16,
+}
+
+#[repr(C)]
+pub struct Foo3 {
+    x: i16,
+    y: bool,
+    z: bool,
+}
+
+#[repr(C)]
+pub struct Foo4 {
+    x: char,
+    y: bool,
+    z: u8,
+}
+
+#[repr(C)]
+pub struct Foo5 {
+    x: u32,
+    y: u16,
+    z: u8,
+    a: bool,
+}
+
+#[repr(C)]
+pub struct FooOversize1 {
+    x: u32,
+    y: u32,
+    z: u32,
+}
+
+#[repr(C)]
+pub struct FooOversize2 {
+    f0: u16,
+    f1: u16,
+    f2: u16,
+    f3: u16,
+    f4: u16,
+}
+
+#[repr(C)]
+pub struct FooFloat1 {
+    x: f32,
+    y: f32,
+}
+
+#[repr(C)]
+pub struct FooFloat2 {
+    x: f64,
+}
+
+#[repr(C)]
+pub struct FooFloat3 {
+    x: f32,
+}
+
+pub mod tests {
+    use {
+        Foo, Foo1, Foo2, Foo3, Foo4, Foo5, FooFloat1, FooFloat2, FooFloat3, FooOversize1,
+        FooOversize2,
+    };
+
+    // ENABLED: i64 @f1()
+    // DISABLED: void @f1(ptr {{.*}}sret
+    #[no_mangle]
+    pub extern "fastcall" fn f1() -> Foo {
+        Foo { x: 1, y: 2 }
+    }
+
+    // CHECK: { i32, i32 } @f2()
+    #[no_mangle]
+    pub extern "Rust" fn f2() -> Foo {
+        Foo { x: 1, y: 2 }
+    }
+
+    // ENABLED: i64 @f3()
+    // DISABLED: void @f3(ptr {{.*}}sret
+    #[no_mangle]
+    pub extern "C" fn f3() -> Foo {
+        Foo { x: 1, y: 2 }
+    }
+
+    // ENABLED: i64 @f4()
+    // DISABLED: void @f4(ptr {{.*}}sret
+    #[no_mangle]
+    pub extern "cdecl" fn f4() -> Foo {
+        Foo { x: 1, y: 2 }
+    }
+
+    // ENABLED: i64 @f5()
+    // DISABLED: void @f5(ptr {{.*}}sret
+    #[no_mangle]
+    pub extern "stdcall" fn f5() -> Foo {
+        Foo { x: 1, y: 2 }
+    }
+
+    // ENABLED: i64 @f6()
+    // DISABLED: void @f6(ptr {{.*}}sret
+    #[no_mangle]
+    pub extern "thiscall" fn f6() -> Foo {
+        Foo { x: 1, y: 2 }
+    }
+
+    // ENABLED: i32 @f7()
+    // DISABLED: void @f7(ptr {{.*}}sret
+    #[no_mangle]
+    pub extern "C" fn f7() -> Foo1 {
+        Foo1 { x: 1 }
+    }
+
+    // ENABLED: i32 @f8()
+    // DISABLED: void @f8(ptr {{.*}}sret
+    #[no_mangle]
+    pub extern "C" fn f8() -> Foo2 {
+        Foo2 { x: true, y: false, z: 5 }
+    }
+
+    // ENABLED: i32 @f9()
+    // DISABLED: void @f9(ptr {{.*}}sret
+    #[no_mangle]
+    pub extern "C" fn f9() -> Foo3 {
+        Foo3 { x: 5, y: false, z: true }
+    }
+
+    // ENABLED: i64 @f10()
+    // DISABLED: void @f10(ptr {{.*}}sret
+    #[no_mangle]
+    pub extern "C" fn f10() -> Foo4 {
+        Foo4 { x: 'x', y: true, z: 170 }
+    }
+
+    // ENABLED: i64 @f11()
+    // DISABLED: void @f11(ptr {{.*}}sret
+    #[no_mangle]
+    pub extern "C" fn f11() -> Foo5 {
+        Foo5 { x: 1, y: 2, z: 3, a: true }
+    }
+
+    // CHECK: void @f12(ptr {{.*}}sret
+    #[no_mangle]
+    pub extern "C" fn f12() -> FooOversize1 {
+        FooOversize1 { x: 1, y: 2, z: 3 }
+    }
+
+    // CHECK: void @f13(ptr {{.*}}sret
+    #[no_mangle]
+    pub extern "C" fn f13() -> FooOversize2 {
+        FooOversize2 { f0: 1, f1: 2, f2: 3, f3: 4, f4: 5 }
+    }
+
+    // ENABLED: i64 @f14()
+    // DISABLED: void @f14(ptr {{.*}}sret
+    #[no_mangle]
+    pub extern "C" fn f14() -> FooFloat1 {
+        FooFloat1 { x: 1.0, y: 1.0 }
+    }
+
+    // ENABLED: double @f15()
+    // DISABLED: void @f15(ptr {{.*}}sret
+    #[no_mangle]
+    pub extern "C" fn f15() -> FooFloat2 {
+        FooFloat2 { x: 1.0 }
+    }
+
+    // ENABLED: float @f16()
+    // DISABLED: void @f16(ptr {{.*}}sret
+    #[no_mangle]
+    pub extern "C" fn f16() -> FooFloat3 {
+        FooFloat3 { x: 1.0 }
+    }
+}
diff --git a/tests/codegen-llvm/regparm-inreg.rs b/tests/codegen-llvm/regparm-inreg.rs
new file mode 100644
index 00000000000..15702804dfd
--- /dev/null
+++ b/tests/codegen-llvm/regparm-inreg.rs
@@ -0,0 +1,125 @@
+// Checks how `regparm` flag works with different calling conventions:
+// marks function arguments as "inreg" like the C/C++ compilers for the platforms.
+// x86 only.
+
+//@ add-core-stubs
+//@ compile-flags: --target i686-unknown-linux-gnu -Cno-prepopulate-passes -Copt-level=3 -Ctarget-feature=+avx
+//@ needs-llvm-components: x86
+
+//@ revisions:regparm0 regparm1 regparm2 regparm3
+//@[regparm0] compile-flags: -Zregparm=0
+//@[regparm1] compile-flags: -Zregparm=1
+//@[regparm2] compile-flags: -Zregparm=2
+//@[regparm3] compile-flags: -Zregparm=3
+
+#![crate_type = "lib"]
+#![no_core]
+#![feature(no_core, lang_items, repr_simd)]
+
+extern crate minicore;
+use minicore::*;
+
+pub mod tests {
+    // regparm doesn't work for "fastcall" calling conv (only 2 inregs)
+    // CHECK: @f1(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 noundef %_3)
+    #[no_mangle]
+    pub extern "fastcall" fn f1(_: i32, _: i32, _: i32) {}
+
+    // regparm0: @f3(i32 noundef %_1, i32 noundef %_2, i32 noundef %_3)
+    // regparm1: @f3(i32 inreg noundef %_1, i32 noundef %_2, i32 noundef %_3)
+    // regparm2: @f3(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 noundef %_3)
+    // regparm3: @f3(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 inreg noundef %_3)
+    #[no_mangle]
+    pub extern "C" fn f3(_: i32, _: i32, _: i32) {}
+
+    // regparm0: @f4(i32 noundef %_1, i32 noundef %_2, i32 noundef %_3)
+    // regparm1: @f4(i32 inreg noundef %_1, i32 noundef %_2, i32 noundef %_3)
+    // regparm2: @f4(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 noundef %_3)
+    // regparm3: @f4(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 inreg noundef %_3)
+    #[no_mangle]
+    pub extern "cdecl" fn f4(_: i32, _: i32, _: i32) {}
+
+    // regparm0: @f5(i32 noundef %_1, i32 noundef %_2, i32 noundef %_3)
+    // regparm1: @f5(i32 inreg noundef %_1, i32 noundef %_2, i32 noundef %_3)
+    // regparm2: @f5(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 noundef %_3)
+    // regparm3: @f5(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 inreg noundef %_3)
+    #[no_mangle]
+    pub extern "stdcall" fn f5(_: i32, _: i32, _: i32) {}
+
+    // regparm doesn't work for thiscall
+    // CHECK: @f6(i32 noundef %_1, i32 noundef %_2, i32 noundef %_3)
+    #[no_mangle]
+    pub extern "thiscall" fn f6(_: i32, _: i32, _: i32) {}
+
+    struct S1 {
+        x1: i32,
+    }
+    // regparm0: @f7(i32 noundef %_1, i32 noundef %_2, i32 noundef %_3, i32 noundef %_4)
+    // regparm1: @f7(i32 inreg noundef %_1, i32 noundef %_2, i32 noundef %_3, i32 noundef %_4)
+    // regparm2: @f7(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 noundef %_3, i32 noundef %_4)
+    // regparm3: @f7(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 inreg noundef %_3,
+    // regparm3-SAME: i32 noundef %_4)
+    #[no_mangle]
+    pub extern "C" fn f7(_: i32, _: i32, _: S1, _: i32) {}
+
+    #[repr(C)]
+    struct S2 {
+        x1: i32,
+        x2: i32,
+    }
+    // regparm0: @f8(i32 noundef %_1, i32 noundef %_2, ptr {{.*}} %_3, i32 noundef %_4)
+    // regparm1: @f8(i32 inreg noundef %_1, i32 noundef %_2, ptr {{.*}} %_3, i32 noundef %_4)
+    // regparm2: @f8(i32 inreg noundef %_1, i32 inreg noundef %_2, ptr {{.*}} %_3, i32 noundef %_4)
+    // regparm3: @f8(i32 inreg noundef %_1, i32 inreg noundef %_2, ptr {{.*}} %_3,
+    // regparm3-SAME: i32 inreg noundef %_4)
+    #[no_mangle]
+    pub extern "C" fn f8(_: i32, _: i32, _: S2, _: i32) {}
+
+    // regparm0: @f9(i1 noundef zeroext %_1, i16 noundef signext %_2, i64 noundef %_3,
+    // regparm0-SAME: i128 noundef %_4)
+    // regparm1: @f9(i1 inreg noundef zeroext %_1, i16 noundef signext %_2, i64 noundef %_3,
+    // regparm1-SAME: i128 noundef %_4)
+    // regparm2: @f9(i1 inreg noundef zeroext %_1, i16 inreg noundef signext %_2, i64 noundef %_3,
+    // regparm2-SAME: i128 noundef %_4)
+    // regparm3: @f9(i1 inreg noundef zeroext %_1, i16 inreg noundef signext %_2, i64 noundef %_3,
+    // regparm3-SAME: i128 noundef %_4)
+    #[no_mangle]
+    pub extern "C" fn f9(_: bool, _: i16, _: i64, _: u128) {}
+
+    // regparm0: @f10(float noundef %_1, double noundef %_2, i1 noundef zeroext %_3,
+    // regparm0-SAME: i16 noundef signext %_4)
+    // regparm1: @f10(float noundef %_1, double noundef %_2, i1 inreg noundef zeroext %_3,
+    // regparm1-SAME: i16 noundef signext %_4)
+    // regparm2: @f10(float noundef %_1, double noundef %_2, i1 inreg noundef zeroext %_3,
+    // regparm2-SAME: i16 inreg noundef signext %_4)
+    // regparm3: @f10(float noundef %_1, double noundef %_2, i1 inreg noundef zeroext %_3,
+    // regparm3-SAME: i16 inreg noundef signext %_4)
+    #[no_mangle]
+    pub extern "C" fn f10(_: f32, _: f64, _: bool, _: i16) {}
+
+    #[allow(non_camel_case_types)]
+    #[repr(simd)]
+    pub struct __m128([f32; 4]);
+
+    // regparm0: @f11(i32 noundef %_1, <4 x float> %_2, i32 noundef %_3, i32 noundef %_4)
+    // regparm1: @f11(i32 inreg noundef %_1, <4 x float> %_2, i32 noundef %_3, i32 noundef %_4)
+    // regparm2: @f11(i32 inreg noundef %_1, <4 x float> %_2, i32 inreg noundef %_3,
+    // regparm2-SAME: i32 noundef %_4)
+    // regparm3: @f11(i32 inreg noundef %_1, <4 x float> %_2, i32 inreg noundef %_3,
+    // regparm3-SAME: i32 inreg noundef %_4)
+    #[no_mangle]
+    pub extern "C" fn f11(_: i32, _: __m128, _: i32, _: i32) {}
+
+    #[allow(non_camel_case_types)]
+    #[repr(simd)]
+    pub struct __m256([f32; 8]);
+
+    // regparm0: @f12(i32 noundef %_1, <8 x float> %_2, i32 noundef %_3, i32 noundef %_4)
+    // regparm1: @f12(i32 inreg noundef %_1, <8 x float> %_2, i32 noundef %_3, i32 noundef %_4)
+    // regparm2: @f12(i32 inreg noundef %_1, <8 x float> %_2, i32 inreg noundef %_3,
+    // regparm2-SAME: i32 noundef %_4)
+    // regparm3: @f12(i32 inreg noundef %_1, <8 x float> %_2, i32 inreg noundef %_3,
+    // regparm3-SAME: i32 inreg noundef %_4)
+    #[no_mangle]
+    pub extern "C" fn f12(_: i32, _: __m256, _: i32, _: i32) {}
+}
diff --git a/tests/codegen-llvm/remap_path_prefix/aux_mod.rs b/tests/codegen-llvm/remap_path_prefix/aux_mod.rs
new file mode 100644
index 00000000000..3217e9e51e7
--- /dev/null
+++ b/tests/codegen-llvm/remap_path_prefix/aux_mod.rs
@@ -0,0 +1,6 @@
+//@ ignore-auxiliary (used by `./main.rs`)
+
+#[inline]
+pub fn some_aux_mod_function() -> i32 {
+    1234
+}
diff --git a/tests/codegen-llvm/remap_path_prefix/auxiliary/remap_path_prefix_aux.rs b/tests/codegen-llvm/remap_path_prefix/auxiliary/remap_path_prefix_aux.rs
new file mode 100644
index 00000000000..7afc16ec72f
--- /dev/null
+++ b/tests/codegen-llvm/remap_path_prefix/auxiliary/remap_path_prefix_aux.rs
@@ -0,0 +1,8 @@
+//
+
+//@ compile-flags: -g  --remap-path-prefix={{cwd}}=/the/aux-cwd --remap-path-prefix={{src-base}}/remap_path_prefix/auxiliary=/the/aux-src
+
+#[inline]
+pub fn some_aux_function() -> i32 {
+    1234
+}
diff --git a/tests/codegen-llvm/remap_path_prefix/auxiliary/xcrate-generic.rs b/tests/codegen-llvm/remap_path_prefix/auxiliary/xcrate-generic.rs
new file mode 100644
index 00000000000..9d5cdfe063b
--- /dev/null
+++ b/tests/codegen-llvm/remap_path_prefix/auxiliary/xcrate-generic.rs
@@ -0,0 +1,8 @@
+//
+//@ compile-flags: -g  --remap-path-prefix={{cwd}}=/the/aux-cwd --remap-path-prefix={{src-base}}/remap_path_prefix/auxiliary=/the/aux-src
+
+#![crate_type = "lib"]
+
+pub fn foo<T: Default>() -> T {
+    T::default()
+}
diff --git a/tests/codegen-llvm/remap_path_prefix/issue-73167-remap-std.rs b/tests/codegen-llvm/remap_path_prefix/issue-73167-remap-std.rs
new file mode 100644
index 00000000000..eb610168dd3
--- /dev/null
+++ b/tests/codegen-llvm/remap_path_prefix/issue-73167-remap-std.rs
@@ -0,0 +1,15 @@
+//@ ignore-windows
+
+//@ compile-flags: -g  -C no-prepopulate-passes -Z simulate-remapped-rust-src-base=/rustc/xyz
+
+// Here we check that importing std will not cause real path to std source files
+// to leak. If rustc was compiled with remap-debuginfo = true, this should be
+// true automatically. If paths to std library hasn't been remapped, we use the
+// above simulate-remapped-rust-src-base option to do it temporarily
+
+// CHECK: !DIFile(filename: "{{/rustc/.*/library/std/src/panic.rs}}"
+fn main() {
+    std::thread::spawn(|| {
+        println!("hello");
+    });
+}
diff --git a/tests/codegen-llvm/remap_path_prefix/main.rs b/tests/codegen-llvm/remap_path_prefix/main.rs
new file mode 100644
index 00000000000..7d17b3b67cf
--- /dev/null
+++ b/tests/codegen-llvm/remap_path_prefix/main.rs
@@ -0,0 +1,28 @@
+//@ ignore-windows
+//
+
+//@ compile-flags: -g  -C no-prepopulate-passes --remap-path-prefix={{cwd}}=/the/cwd --remap-path-prefix={{src-base}}=/the/src -Zinline-mir=no
+//@ aux-build:remap_path_prefix_aux.rs
+
+extern crate remap_path_prefix_aux;
+
+// Here we check that submodules and include files are found using the path without
+// remapping. This test requires that rustc is called with an absolute path.
+mod aux_mod;
+include!("aux_mod.rs");
+
+// Here we check that the expansion of the file!() macro is mapped.
+// CHECK: @alloc_5761061597a97f66e13ef2ff92712c4b = private unnamed_addr constant [34 x i8] c"/the/src/remap_path_prefix/main.rs"
+pub static FILE_PATH: &'static str = file!();
+
+fn main() {
+    remap_path_prefix_aux::some_aux_function();
+    aux_mod::some_aux_mod_function();
+    some_aux_mod_function();
+}
+
+// Here we check that local debuginfo is mapped correctly.
+// CHECK: !DIFile(filename: "/the/src/remap_path_prefix/main.rs", directory: ""
+
+// And here that debuginfo from other crates are expanded to absolute paths.
+// CHECK: !DIFile(filename: "/the/aux-src/remap_path_prefix_aux.rs", directory: ""
diff --git a/tests/codegen-llvm/remap_path_prefix/xcrate-generic.rs b/tests/codegen-llvm/remap_path_prefix/xcrate-generic.rs
new file mode 100644
index 00000000000..db69b72d904
--- /dev/null
+++ b/tests/codegen-llvm/remap_path_prefix/xcrate-generic.rs
@@ -0,0 +1,14 @@
+//@ ignore-windows
+//@ compile-flags: -g -C metadata=foo -C no-prepopulate-passes
+//@ aux-build:xcrate-generic.rs
+
+#![crate_type = "lib"]
+
+extern crate xcrate_generic;
+
+pub fn foo() {
+    println!("{}", xcrate_generic::foo::<u32>());
+}
+
+// Here we check that local debuginfo is mapped correctly.
+// CHECK: !DIFile(filename: "/the/aux-src/xcrate-generic.rs", directory: ""
diff --git a/tests/codegen-llvm/repeat-operand-zero-len.rs b/tests/codegen-llvm/repeat-operand-zero-len.rs
new file mode 100644
index 00000000000..b4cec42a07c
--- /dev/null
+++ b/tests/codegen-llvm/repeat-operand-zero-len.rs
@@ -0,0 +1,28 @@
+//@ compile-flags: -Copt-level=1 -Cno-prepopulate-passes
+
+// This test is here to hit the `Rvalue::Repeat` case in `codegen_rvalue_operand`.
+// It only applies when the resulting array is a ZST, so the test is written in
+// such a way as to keep MIR optimizations from seeing that fact and removing
+// the local and statement altogether. (At the time of writing, no other codegen
+// test hit that code path, nor did a stage 2 build of the compiler.)
+
+#![crate_type = "lib"]
+
+#[repr(transparent)]
+pub struct Wrapper<T, const N: usize>([T; N]);
+
+// CHECK-LABEL: define {{.+}}do_repeat{{.+}}(i32 noundef %x)
+// CHECK-NEXT: start:
+// CHECK-NOT: alloca
+// CHECK-NEXT: ret void
+#[inline(never)]
+pub fn do_repeat<T: Copy, const N: usize>(x: T) -> Wrapper<T, N> {
+    Wrapper([x; N])
+}
+
+// CHECK-LABEL: @trigger_repeat_zero_len
+#[no_mangle]
+pub fn trigger_repeat_zero_len() -> Wrapper<u32, 0> {
+    // CHECK: call void {{.+}}do_repeat{{.+}}(i32 noundef 4)
+    do_repeat(4)
+}
diff --git a/tests/codegen-llvm/repeat-operand-zst-elem.rs b/tests/codegen-llvm/repeat-operand-zst-elem.rs
new file mode 100644
index 00000000000..c3637759afa
--- /dev/null
+++ b/tests/codegen-llvm/repeat-operand-zst-elem.rs
@@ -0,0 +1,28 @@
+//@ compile-flags: -Copt-level=1 -Cno-prepopulate-passes
+
+// This test is here to hit the `Rvalue::Repeat` case in `codegen_rvalue_operand`.
+// It only applies when the resulting array is a ZST, so the test is written in
+// such a way as to keep MIR optimizations from seeing that fact and removing
+// the local and statement altogether. (At the time of writing, no other codegen
+// test hit that code path, nor did a stage 2 build of the compiler.)
+
+#![crate_type = "lib"]
+
+#[repr(transparent)]
+pub struct Wrapper<T, const N: usize>([T; N]);
+
+// CHECK-LABEL: define {{.+}}do_repeat{{.+}}()
+// CHECK-NEXT: start:
+// CHECK-NOT: alloca
+// CHECK-NEXT: ret void
+#[inline(never)]
+pub fn do_repeat<T: Copy, const N: usize>(x: T) -> Wrapper<T, N> {
+    Wrapper([x; N])
+}
+
+// CHECK-LABEL: @trigger_repeat_zst_elem
+#[no_mangle]
+pub fn trigger_repeat_zst_elem() -> Wrapper<(), 8> {
+    // CHECK: call void {{.+}}do_repeat{{.+}}()
+    do_repeat(())
+}
diff --git a/tests/codegen-llvm/repeat-trusted-len.rs b/tests/codegen-llvm/repeat-trusted-len.rs
new file mode 100644
index 00000000000..95379535971
--- /dev/null
+++ b/tests/codegen-llvm/repeat-trusted-len.rs
@@ -0,0 +1,20 @@
+//@ compile-flags: -Copt-level=3
+//
+
+#![crate_type = "lib"]
+
+use std::iter;
+
+// CHECK-LABEL: @repeat_take_collect
+#[no_mangle]
+pub fn repeat_take_collect() -> Vec<u8> {
+    // CHECK: call void @llvm.memset.{{.+}}(ptr {{.*}}align 1{{.*}} %{{.*}}, i8 42, i{{[0-9]+}} 100000, i1 false)
+    iter::repeat(42).take(100000).collect()
+}
+
+// CHECK-LABEL: @repeat_with_take_collect
+#[no_mangle]
+pub fn repeat_with_take_collect() -> Vec<u8> {
+    // CHECK: call void @llvm.memset.{{.+}}(ptr {{.*}}align 1{{.*}} %{{.*}}, i8 13, i{{[0-9]+}} 12345, i1 false)
+    iter::repeat_with(|| 13).take(12345).collect()
+}
diff --git a/tests/codegen-llvm/repr/transparent-byval-struct-ptr.rs b/tests/codegen-llvm/repr/transparent-byval-struct-ptr.rs
new file mode 100644
index 00000000000..0918884144f
--- /dev/null
+++ b/tests/codegen-llvm/repr/transparent-byval-struct-ptr.rs
@@ -0,0 +1,111 @@
+//@ add-core-stubs
+//@ revisions: i686-linux i686-freebsd x64-linux x64-apple
+//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes
+
+//@[i686-linux] compile-flags: --target i686-unknown-linux-gnu
+//@[i686-linux] needs-llvm-components: x86
+//@[i686-freebsd] compile-flags: --target i686-unknown-freebsd
+//@[i686-freebsd] needs-llvm-components: x86
+//@[x64-linux] compile-flags: --target x86_64-unknown-linux-gnu
+//@[x64-linux] needs-llvm-components: x86
+//@[x64-apple] compile-flags: --target x86_64-apple-darwin
+//@[x64-apple] needs-llvm-components: x86
+
+// See ./transparent.rs
+// Some platforms pass large aggregates using immediate arrays in LLVMIR
+// Other platforms pass large aggregates using by-value struct pointer in LLVMIR
+// Yet more platforms pass large aggregates using opaque pointer in LLVMIR
+// This covers the "by-value struct pointer" case.
+
+#![feature(no_core, lang_items, transparent_unions)]
+#![crate_type = "lib"]
+#![no_std]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+impl Copy for BigS {}
+impl Copy for BigU {}
+
+#[repr(C)]
+pub struct BigS([u32; 16]);
+
+#[repr(transparent)]
+pub struct TsBigS(BigS);
+
+#[repr(transparent)]
+pub union TuBigS {
+    field: BigS,
+}
+
+#[repr(transparent)]
+pub enum TeBigS {
+    Variant(BigS),
+}
+
+// CHECK: define{{.*}}void @test_BigS(ptr [[BIGS_RET_ATTRS1:.*]] sret([64 x i8]) [[BIGS_RET_ATTRS2:.*]], ptr [[BIGS_ARG_ATTRS1:.*]] byval([64 x i8]) [[BIGS_ARG_ATTRS2:.*]])
+#[no_mangle]
+pub extern "C" fn test_BigS(_: BigS) -> BigS {
+    loop {}
+}
+
+// CHECK: define{{.*}}void @test_TsBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], ptr [[BIGS_ARG_ATTRS1]] byval([64 x i8]) [[BIGS_ARG_ATTRS2:.*]])
+#[no_mangle]
+pub extern "C" fn test_TsBigS(_: TsBigS) -> TsBigS {
+    loop {}
+}
+
+// CHECK: define{{.*}}void @test_TuBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], ptr [[BIGS_ARG_ATTRS1]] byval([64 x i8]) [[BIGS_ARG_ATTRS2:.*]])
+#[no_mangle]
+pub extern "C" fn test_TuBigS(_: TuBigS) -> TuBigS {
+    loop {}
+}
+
+// CHECK: define{{.*}}void @test_TeBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], ptr [[BIGS_ARG_ATTRS1]] byval([64 x i8]) [[BIGS_ARG_ATTRS2]])
+#[no_mangle]
+pub extern "C" fn test_TeBigS(_: TeBigS) -> TeBigS {
+    loop {}
+}
+
+#[repr(C)]
+pub union BigU {
+    foo: [u32; 16],
+}
+
+#[repr(transparent)]
+pub struct TsBigU(BigU);
+
+#[repr(transparent)]
+pub union TuBigU {
+    field: BigU,
+}
+
+#[repr(transparent)]
+pub enum TeBigU {
+    Variant(BigU),
+}
+
+// CHECK: define{{.*}}void @test_BigU(ptr [[BIGU_RET_ATTRS1:.*]] sret([64 x i8]) [[BIGU_RET_ATTRS2:.*]], ptr [[BIGU_ARG_ATTRS1:.*]] byval([64 x i8]) [[BIGU_ARG_ATTRS2:.*]])
+#[no_mangle]
+pub extern "C" fn test_BigU(_: BigU) -> BigU {
+    loop {}
+}
+
+// CHECK: define{{.*}}void @test_TsBigU(ptr [[BIGU_RET_ATTRS1:.*]] sret([64 x i8]) [[BIGU_RET_ATTRS2:.*]], ptr [[BIGU_ARG_ATTRS1]] byval([64 x i8]) [[BIGU_ARG_ATTRS2]])
+#[no_mangle]
+pub extern "C" fn test_TsBigU(_: TsBigU) -> TsBigU {
+    loop {}
+}
+
+// CHECK: define{{.*}}void @test_TuBigU(ptr [[BIGU_RET_ATTRS1]] sret([64 x i8]) [[BIGU_RET_ATTRS2:.*]], ptr [[BIGU_ARG_ATTRS1]] byval([64 x i8]) [[BIGU_ARG_ATTRS2]])
+#[no_mangle]
+pub extern "C" fn test_TuBigU(_: TuBigU) -> TuBigU {
+    loop {}
+}
+
+// CHECK: define{{.*}}void @test_TeBigU(ptr [[BIGU_RET_ATTRS1]] sret([64 x i8]) [[BIGU_RET_ATTRS2:.*]], ptr [[BIGU_ARG_ATTRS1]] byval([64 x i8]) [[BIGU_ARG_ATTRS2]])
+#[no_mangle]
+pub extern "C" fn test_TeBigU(_: TeBigU) -> TeBigU {
+    loop {}
+}
diff --git a/tests/codegen-llvm/repr/transparent-imm-array.rs b/tests/codegen-llvm/repr/transparent-imm-array.rs
new file mode 100644
index 00000000000..6dad0447784
--- /dev/null
+++ b/tests/codegen-llvm/repr/transparent-imm-array.rs
@@ -0,0 +1,116 @@
+//@ add-core-stubs
+//@ revisions: arm-linux arm-android armv7-linux armv7-android mips thumb sparc
+//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes
+
+//@[arm-linux] compile-flags: --target arm-unknown-linux-gnueabi
+//@[arm-linux] needs-llvm-components: arm
+//@[arm-android] compile-flags: --target arm-linux-androideabi
+//@[arm-android] needs-llvm-components: arm
+//@[armv7-linux] compile-flags: --target armv7-unknown-linux-gnueabi
+//@[armv7-linux] needs-llvm-components: arm
+//@[armv7-android] compile-flags: --target armv7-linux-androideabi
+//@[armv7-android] needs-llvm-components: arm
+//@[mips] compile-flags: --target mips-unknown-linux-gnu
+//@[mips] needs-llvm-components: mips
+//@[thumb] compile-flags: --target thumbv7neon-linux-androideabi
+//@[thumb] needs-llvm-components: arm
+//@[sparc] compile-flags: --target sparc-unknown-linux-gnu
+//@[sparc] needs-llvm-components: sparc
+
+// See ./transparent.rs
+// Some platforms pass large aggregates using immediate arrays in LLVMIR
+// Other platforms pass large aggregates using by-value struct pointer in LLVMIR
+// Yet more platforms pass large aggregates using opaque pointer in LLVMIR
+// This covers the "immediate array" case.
+
+#![feature(no_core, lang_items, transparent_unions)]
+#![crate_type = "lib"]
+#![no_std]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+impl Copy for BigS {}
+impl Copy for BigU {}
+
+#[repr(C)]
+pub struct BigS([u32; 16]);
+
+#[repr(transparent)]
+pub struct TsBigS(BigS);
+
+#[repr(transparent)]
+pub union TuBigS {
+    field: BigS,
+}
+
+#[repr(transparent)]
+pub enum TeBigS {
+    Variant(BigS),
+}
+
+// CHECK: define void @test_BigS(ptr [[BIGS_RET_ATTRS1:.*]] sret([64 x i8]) [[BIGS_RET_ATTRS2:.*]], [16 x i32]
+#[no_mangle]
+pub extern "C" fn test_BigS(_: BigS) -> BigS {
+    loop {}
+}
+
+// CHECK: define void @test_TsBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], [16 x i32]
+#[no_mangle]
+pub extern "C" fn test_TsBigS(_: TsBigS) -> TsBigS {
+    loop {}
+}
+
+// CHECK: define void @test_TuBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], [16 x i32]
+#[no_mangle]
+pub extern "C" fn test_TuBigS(_: TuBigS) -> TuBigS {
+    loop {}
+}
+
+// CHECK: define void @test_TeBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], [16 x i32]
+#[no_mangle]
+pub extern "C" fn test_TeBigS(_: TeBigS) -> TeBigS {
+    loop {}
+}
+
+#[repr(C)]
+pub union BigU {
+    foo: [u32; 16],
+}
+
+#[repr(transparent)]
+pub struct TsBigU(BigU);
+
+#[repr(transparent)]
+pub union TuBigU {
+    field: BigU,
+}
+
+#[repr(transparent)]
+pub enum TeBigU {
+    Variant(BigU),
+}
+
+// CHECK: define void @test_BigU(ptr [[BIGU_RET_ATTRS1:.*]] sret([64 x i8]) [[BIGU_RET_ATTRS2:.*]], [16 x i32]
+#[no_mangle]
+pub extern "C" fn test_BigU(_: BigU) -> BigU {
+    loop {}
+}
+
+// CHECK: define void @test_TsBigU(ptr [[BIGU_RET_ATTRS1]] sret([64 x i8]) [[BIGU_RET_ATTRS2]], [16 x i32]
+#[no_mangle]
+pub extern "C" fn test_TsBigU(_: TsBigU) -> TsBigU {
+    loop {}
+}
+
+// CHECK: define void @test_TuBigU(ptr [[BIGU_RET_ATTRS1]] sret([64 x i8]) [[BIGU_RET_ATTRS2]], [16 x i32]
+#[no_mangle]
+pub extern "C" fn test_TuBigU(_: TuBigU) -> TuBigU {
+    loop {}
+}
+
+// CHECK: define void @test_TeBigU(ptr [[BIGU_RET_ATTRS1]] sret([64 x i8]) [[BIGU_RET_ATTRS2]], [16 x i32]
+#[no_mangle]
+pub extern "C" fn test_TeBigU(_: TeBigU) -> TeBigU {
+    loop {}
+}
diff --git a/tests/codegen-llvm/repr/transparent-mips64.rs b/tests/codegen-llvm/repr/transparent-mips64.rs
new file mode 100644
index 00000000000..98901350154
--- /dev/null
+++ b/tests/codegen-llvm/repr/transparent-mips64.rs
@@ -0,0 +1,103 @@
+//@ add-core-stubs
+//@ revisions: mips64 mips64el
+//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes
+
+//@[mips64] compile-flags: --target mips64-unknown-linux-gnuabi64
+//@[mips64] needs-llvm-components: mips
+//@[mips64el] compile-flags: --target mips64el-unknown-linux-gnuabi64
+//@[mips64el] needs-llvm-components: mips
+
+// See ./transparent.rs
+
+#![feature(no_core, lang_items, transparent_unions)]
+#![crate_type = "lib"]
+#![no_std]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+impl Copy for BigS {}
+impl Copy for BigU {}
+
+#[repr(C)]
+pub struct BigS([u32; 16]);
+
+#[repr(transparent)]
+pub struct TsBigS(BigS);
+
+#[repr(transparent)]
+pub union TuBigS {
+    field: BigS,
+}
+
+#[repr(transparent)]
+pub enum TeBigS {
+    Variant(BigS),
+}
+
+// CHECK: define void @test_BigS(ptr [[BIGS_RET_ATTRS1:.*]] sret([64 x i8]) [[BIGS_RET_ATTRS2:.*]], [8 x i64]
+#[no_mangle]
+pub extern "C" fn test_BigS(_: BigS) -> BigS {
+    loop {}
+}
+
+// CHECK: define void @test_TsBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], [8 x i64]
+#[no_mangle]
+pub extern "C" fn test_TsBigS(_: TsBigS) -> TsBigS {
+    loop {}
+}
+
+// CHECK: define void @test_TuBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], [8 x i64]
+#[no_mangle]
+pub extern "C" fn test_TuBigS(_: TuBigS) -> TuBigS {
+    loop {}
+}
+
+// CHECK: define void @test_TeBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], [8 x i64]
+#[no_mangle]
+pub extern "C" fn test_TeBigS(_: TeBigS) -> TeBigS {
+    loop {}
+}
+
+#[repr(C)]
+pub union BigU {
+    foo: [u32; 16],
+}
+
+#[repr(transparent)]
+pub struct TsBigU(BigU);
+
+#[repr(transparent)]
+pub union TuBigU {
+    field: BigU,
+}
+
+#[repr(transparent)]
+pub enum TeBigU {
+    Variant(BigU),
+}
+
+// CHECK: define void @test_BigU(ptr [[BIGU_RET_ATTRS1:.*]] sret([64 x i8]) [[BIGU_RET_ATTRS2:.*]], [8 x i64]
+#[no_mangle]
+pub extern "C" fn test_BigU(_: BigU) -> BigU {
+    loop {}
+}
+
+// CHECK: define void @test_TsBigU(ptr [[BIGU_RET_ATTRS1]] sret([64 x i8]) [[BIGU_RET_ATTRS2]], [8 x i64]
+#[no_mangle]
+pub extern "C" fn test_TsBigU(_: TsBigU) -> TsBigU {
+    loop {}
+}
+
+// CHECK: define void @test_TuBigU(ptr [[BIGU_RET_ATTRS1]] sret([64 x i8]) [[BIGU_RET_ATTRS2]], [8 x i64]
+#[no_mangle]
+pub extern "C" fn test_TuBigU(_: TuBigU) -> TuBigU {
+    loop {}
+}
+
+// CHECK: define void @test_TeBigU(ptr [[BIGU_RET_ATTRS1]] sret([64 x i8]) [[BIGU_RET_ATTRS2]], [8 x i64]
+#[no_mangle]
+pub extern "C" fn test_TeBigU(_: TeBigU) -> TeBigU {
+    loop {}
+}
diff --git a/tests/codegen-llvm/repr/transparent-opaque-ptr.rs b/tests/codegen-llvm/repr/transparent-opaque-ptr.rs
new file mode 100644
index 00000000000..7911370c478
--- /dev/null
+++ b/tests/codegen-llvm/repr/transparent-opaque-ptr.rs
@@ -0,0 +1,109 @@
+//@ add-core-stubs
+//@ revisions: aarch64-linux aarch64-darwin wasm32-wasip1
+//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes
+
+//@[aarch64-linux] compile-flags: --target aarch64-unknown-linux-gnu
+//@[aarch64-linux] needs-llvm-components: aarch64
+//@[aarch64-darwin] compile-flags: --target aarch64-apple-darwin
+//@[aarch64-darwin] needs-llvm-components: aarch64
+//@[wasm32-wasip1] compile-flags: --target wasm32-wasip1
+//@[wasm32-wasip1] needs-llvm-components: webassembly
+
+// See ./transparent.rs
+// Some platforms pass large aggregates using immediate arrays in LLVMIR
+// Other platforms pass large aggregates using by-value struct pointer in LLVMIR
+// Yet more platforms pass large aggregates using opaque pointer in LLVMIR
+// This covers the "opaque pointer" case.
+
+#![feature(no_core, lang_items, transparent_unions)]
+#![crate_type = "lib"]
+#![no_std]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+impl Copy for BigS {}
+impl Copy for BigU {}
+
+#[repr(C)]
+pub struct BigS([u32; 16]);
+
+#[repr(transparent)]
+pub struct TsBigS(BigS);
+
+#[repr(transparent)]
+pub union TuBigS {
+    field: BigS,
+}
+
+#[repr(transparent)]
+pub enum TeBigS {
+    Variant(BigS),
+}
+
+// CHECK: define{{.*}}void @test_BigS(ptr [[BIGS_RET_ATTRS1:.*]] sret([64 x i8]) [[BIGS_RET_ATTRS2:.*]], ptr [[BIGS_ARG_ATTRS1:.*]])
+#[no_mangle]
+pub extern "C" fn test_BigS(_: BigS) -> BigS {
+    loop {}
+}
+
+// CHECK: define{{.*}}void @test_TsBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], ptr [[BIGS_ARG_ATTRS1]])
+#[no_mangle]
+pub extern "C" fn test_TsBigS(_: TsBigS) -> TsBigS {
+    loop {}
+}
+
+// CHECK: define{{.*}}void @test_TuBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], ptr [[BIGS_ARG_ATTRS1]])
+#[no_mangle]
+pub extern "C" fn test_TuBigS(_: TuBigS) -> TuBigS {
+    loop {}
+}
+
+// CHECK: define{{.*}}void @test_TeBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], ptr [[BIGS_ARG_ATTRS1]])
+#[no_mangle]
+pub extern "C" fn test_TeBigS(_: TeBigS) -> TeBigS {
+    loop {}
+}
+
+#[repr(C)]
+pub union BigU {
+    foo: [u32; 16],
+}
+
+#[repr(transparent)]
+pub struct TsBigU(BigU);
+
+#[repr(transparent)]
+pub union TuBigU {
+    field: BigU,
+}
+
+#[repr(transparent)]
+pub enum TeBigU {
+    Variant(BigU),
+}
+
+// CHECK: define{{.*}}void @test_BigU(ptr [[BIGU_RET_ATTRS1:.*]] sret([64 x i8]) [[BIGU_RET_ATTRS2:.*]], ptr [[BIGU_ARG_ATTRS1:.*]])
+#[no_mangle]
+pub extern "C" fn test_BigU(_: BigU) -> BigU {
+    loop {}
+}
+
+// CHECK: define{{.*}}void @test_TsBigU(ptr [[BIGU_RET_ATTRS1:.*]] sret([64 x i8]) [[BIGU_RET_ATTRS2:.*]], ptr [[BIGU_ARG_ATTRS1]])
+#[no_mangle]
+pub extern "C" fn test_TsBigU(_: TsBigU) -> TsBigU {
+    loop {}
+}
+
+// CHECK: define{{.*}}void @test_TuBigU(ptr [[BIGU_RET_ATTRS1]] sret([64 x i8]) [[BIGU_RET_ATTRS2:.*]], ptr [[BIGU_ARG_ATTRS1]])
+#[no_mangle]
+pub extern "C" fn test_TuBigU(_: TuBigU) -> TuBigU {
+    loop {}
+}
+
+// CHECK: define{{.*}}void @test_TeBigU(ptr [[BIGU_RET_ATTRS1]] sret([64 x i8]) [[BIGU_RET_ATTRS2:.*]], ptr [[BIGU_ARG_ATTRS1]])
+#[no_mangle]
+pub extern "C" fn test_TeBigU(_: TeBigU) -> TeBigU {
+    loop {}
+}
diff --git a/tests/codegen-llvm/repr/transparent-sparc64.rs b/tests/codegen-llvm/repr/transparent-sparc64.rs
new file mode 100644
index 00000000000..62bfc8a5fce
--- /dev/null
+++ b/tests/codegen-llvm/repr/transparent-sparc64.rs
@@ -0,0 +1,113 @@
+//@ add-core-stubs
+//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes --target sparc64-unknown-linux-gnu
+//@ needs-llvm-components: sparc
+
+// See ./transparent.rs
+
+#![feature(no_core, lang_items, transparent_unions)]
+#![crate_type = "lib"]
+#![no_std]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+impl Copy for BigS {}
+impl Copy for BigU {}
+
+#[repr(C)]
+pub struct BigS([u32; 16]);
+
+#[repr(transparent)]
+pub struct TsBigS(BigS);
+
+#[repr(transparent)]
+pub union TuBigS {
+    field: BigS,
+}
+
+#[repr(transparent)]
+pub enum TeBigS {
+    Variant(BigS),
+}
+
+// CHECK: define{{.*}}void @test_BigS(ptr [[BIGS_RET_ATTRS1:.*]] sret([64 x i8]) [[BIGS_RET_ATTRS2:.*]], ptr
+// CHECK-NOT: byval
+// CHECK-SAME: %{{[0-9a-z_]+}})
+#[no_mangle]
+pub extern "C" fn test_BigS(_: BigS) -> BigS {
+    loop {}
+}
+
+// CHECK: define{{.*}}void @test_TsBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], ptr
+// CHECK-NOT: byval
+// CHECK-SAME: %{{[0-9a-z_]+}})
+#[no_mangle]
+pub extern "C" fn test_TsBigS(_: TsBigS) -> TsBigS {
+    loop {}
+}
+
+// CHECK: define{{.*}}void @test_TuBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], ptr
+// CHECK-NOT: byval
+// CHECK-SAME: %{{[0-9a-z_]+}})
+#[no_mangle]
+pub extern "C" fn test_TuBigS(_: TuBigS) -> TuBigS {
+    loop {}
+}
+
+// CHECK: define{{.*}}void @test_TeBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], ptr
+// CHECK-NOT: byval
+// CHECK-SAME: %{{[0-9a-z_]+}})
+#[no_mangle]
+pub extern "C" fn test_TeBigS(_: TeBigS) -> TeBigS {
+    loop {}
+}
+
+#[repr(C)]
+pub union BigU {
+    foo: [u32; 16],
+}
+
+#[repr(transparent)]
+pub struct TsBigU(BigU);
+
+#[repr(transparent)]
+pub union TuBigU {
+    field: BigU,
+}
+
+#[repr(transparent)]
+pub enum TeBigU {
+    Variant(BigU),
+}
+
+// CHECK: define{{.*}}void @test_BigU(ptr [[BIGU_RET_ATTRS1:.*]] sret([64 x i8]) [[BIGU_RET_ATTRS2:.*]], ptr
+// CHECK-NOT: byval
+// CHECK-SAME: %{{[0-9a-z_]+}})
+#[no_mangle]
+pub extern "C" fn test_BigU(_: BigU) -> BigU {
+    loop {}
+}
+
+// CHECK: define{{.*}}void @test_TsBigU(ptr [[BIGU_RET_ATTRS1:.*]] sret([64 x i8]) [[BIGU_RET_ATTRS2:.*]], ptr
+// CHECK-NOT: byval
+// CHECK-SAME: %{{[0-9a-z_]+}})
+#[no_mangle]
+pub extern "C" fn test_TsBigU(_: TsBigU) -> TsBigU {
+    loop {}
+}
+
+// CHECK: define{{.*}}void @test_TuBigU(ptr [[BIGU_RET_ATTRS1]] sret([64 x i8]) [[BIGU_RET_ATTRS2:.*]], ptr
+// CHECK-NOT: byval
+// CHECK-SAME: %{{[0-9a-z_]+}})
+#[no_mangle]
+pub extern "C" fn test_TuBigU(_: TuBigU) -> TuBigU {
+    loop {}
+}
+
+// CHECK: define{{.*}}void @test_TeBigU(ptr [[BIGU_RET_ATTRS1]] sret([64 x i8]) [[BIGU_RET_ATTRS2:.*]], ptr
+// CHECK-NOT: byval
+// CHECK-SAME: %{{[0-9a-z_]+}})
+#[no_mangle]
+pub extern "C" fn test_TeBigU(_: TeBigU) -> TeBigU {
+    loop {}
+}
diff --git a/tests/codegen-llvm/repr/transparent-sysv64.rs b/tests/codegen-llvm/repr/transparent-sysv64.rs
new file mode 100644
index 00000000000..3efc3f7c391
--- /dev/null
+++ b/tests/codegen-llvm/repr/transparent-sysv64.rs
@@ -0,0 +1,49 @@
+//@ add-core-stubs
+//@ revisions: linux apple win
+//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes
+
+//@[linux] compile-flags: --target x86_64-unknown-linux-gnu
+//@[linux] needs-llvm-components: x86
+//@[apple] compile-flags: --target x86_64-apple-darwin
+//@[apple] needs-llvm-components: x86
+//@[win] compile-flags: --target x86_64-pc-windows-msvc
+//@[win] needs-llvm-components: x86
+
+#![feature(no_core, lang_items)]
+#![crate_type = "lib"]
+#![no_std]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+#[repr(C)]
+pub struct Rgb8 {
+    r: u8,
+    g: u8,
+    b: u8,
+}
+
+#[repr(transparent)]
+pub struct Rgb8Wrap(Rgb8);
+
+// CHECK: i24 @test_Rgb8Wrap(i24{{( %0)?}})
+#[no_mangle]
+pub extern "sysv64" fn test_Rgb8Wrap(_: Rgb8Wrap) -> Rgb8Wrap {
+    loop {}
+}
+
+#[repr(C)]
+pub union FloatBits {
+    float: f32,
+    bits: u32,
+}
+
+#[repr(transparent)]
+pub struct SmallUnion(FloatBits);
+
+// CHECK: i32 @test_SmallUnion(i32{{( %0)?}})
+#[no_mangle]
+pub extern "sysv64" fn test_SmallUnion(_: SmallUnion) -> SmallUnion {
+    loop {}
+}
diff --git a/tests/codegen-llvm/repr/transparent.rs b/tests/codegen-llvm/repr/transparent.rs
new file mode 100644
index 00000000000..29b627462a4
--- /dev/null
+++ b/tests/codegen-llvm/repr/transparent.rs
@@ -0,0 +1,221 @@
+//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes
+//@ ignore-riscv64 riscv64 has an i128 type used with test_Vector
+//@ ignore-s390x s390x with default march passes vector types per reference
+//@ ignore-loongarch64 see codegen/loongarch-abi for loongarch function call tests
+
+// This codegen test embeds assumptions about how certain "C" psABIs are handled
+// so it doesn't apply to all architectures or even all OS
+// For RISCV: see codegen/riscv-abi
+// For LoongArch: see codegen/loongarch-abi
+
+#![crate_type = "lib"]
+#![feature(repr_simd, transparent_unions, arm_target_feature, mips_target_feature)]
+
+use std::marker::PhantomData;
+
+#[derive(Copy, Clone)]
+pub struct Zst1;
+#[derive(Copy, Clone)]
+pub struct Zst2(());
+
+#[derive(Copy, Clone)]
+#[repr(transparent)]
+pub struct F32(f32);
+
+// CHECK: define{{.*}}float @test_F32(float noundef %_1)
+#[no_mangle]
+pub extern "C" fn test_F32(_: F32) -> F32 {
+    loop {}
+}
+
+#[repr(transparent)]
+pub struct Ptr(*mut u8);
+
+// CHECK: define{{.*}}ptr @test_Ptr(ptr noundef %_1)
+#[no_mangle]
+pub extern "C" fn test_Ptr(_: Ptr) -> Ptr {
+    loop {}
+}
+
+#[repr(transparent)]
+pub struct WithZst(u64, Zst1);
+
+// CHECK: define{{.*}}i64 @test_WithZst(i64 noundef %_1)
+#[no_mangle]
+pub extern "C" fn test_WithZst(_: WithZst) -> WithZst {
+    loop {}
+}
+
+#[repr(transparent)]
+pub struct WithZeroSizedArray(*const f32, [i8; 0]);
+
+// CHECK: define{{.*}}ptr @test_WithZeroSizedArray(ptr noundef %_1)
+#[no_mangle]
+pub extern "C" fn test_WithZeroSizedArray(_: WithZeroSizedArray) -> WithZeroSizedArray {
+    loop {}
+}
+
+#[repr(transparent)]
+pub struct Generic<T>(T);
+
+// CHECK: define{{.*}}double @test_Generic(double noundef %_1)
+#[no_mangle]
+pub extern "C" fn test_Generic(_: Generic<f64>) -> Generic<f64> {
+    loop {}
+}
+
+#[repr(transparent)]
+pub struct GenericPlusZst<T>(T, Zst2);
+
+#[repr(u8)]
+pub enum Bool {
+    True,
+    False,
+    FileNotFound,
+}
+
+// CHECK: define{{( dso_local)?}} noundef{{( zeroext)?( range\(i8 0, 3\))?}} i8 @test_Gpz(i8 noundef{{( zeroext)?( range\(i8 0, 3\))?}} %_1)
+#[no_mangle]
+pub extern "C" fn test_Gpz(_: GenericPlusZst<Bool>) -> GenericPlusZst<Bool> {
+    loop {}
+}
+
+#[repr(transparent)]
+pub struct LifetimePhantom<'a, T: 'a>(*const T, PhantomData<&'a T>);
+
+// CHECK: define{{.*}}ptr @test_LifetimePhantom(ptr noundef %_1)
+#[no_mangle]
+pub extern "C" fn test_LifetimePhantom(_: LifetimePhantom<i16>) -> LifetimePhantom<i16> {
+    loop {}
+}
+
+// This works despite current alignment resrictions because PhantomData is always align(1)
+#[repr(transparent)]
+pub struct UnitPhantom<T, U> {
+    val: T,
+    unit: PhantomData<U>,
+}
+
+pub struct Px;
+
+// CHECK: define{{.*}}float @test_UnitPhantom(float noundef %_1)
+#[no_mangle]
+pub extern "C" fn test_UnitPhantom(_: UnitPhantom<f32, Px>) -> UnitPhantom<f32, Px> {
+    loop {}
+}
+
+#[repr(transparent)]
+pub struct TwoZsts(Zst1, i8, Zst2);
+
+// CHECK: define{{( dso_local)?}} noundef{{( signext)?}} i8 @test_TwoZsts(i8 noundef{{( signext)?}} %_1)
+#[no_mangle]
+pub extern "C" fn test_TwoZsts(_: TwoZsts) -> TwoZsts {
+    loop {}
+}
+
+#[repr(transparent)]
+pub struct Nested1(Zst2, Generic<f64>);
+
+// CHECK: define{{.*}}double @test_Nested1(double noundef %_1)
+#[no_mangle]
+pub extern "C" fn test_Nested1(_: Nested1) -> Nested1 {
+    loop {}
+}
+
+#[repr(transparent)]
+pub struct Nested2(Nested1, Zst1);
+
+// CHECK: define{{.*}}double @test_Nested2(double noundef %_1)
+#[no_mangle]
+pub extern "C" fn test_Nested2(_: Nested2) -> Nested2 {
+    loop {}
+}
+
+#[repr(simd)]
+struct f32x4([f32; 4]);
+
+#[repr(transparent)]
+pub struct Vector(f32x4);
+
+// CHECK: define{{.*}}<4 x float> @test_Vector(<4 x float> %_1)
+#[no_mangle]
+#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))]
+#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))]
+#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))]
+#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))]
+pub extern "C" fn test_Vector(_: Vector) -> Vector {
+    loop {}
+}
+
+trait Mirror {
+    type It: ?Sized;
+}
+impl<T: ?Sized> Mirror for T {
+    type It = Self;
+}
+
+#[repr(transparent)]
+pub struct StructWithProjection(<f32 as Mirror>::It);
+
+// CHECK: define{{.*}}float @test_Projection(float noundef %_1)
+#[no_mangle]
+pub extern "C" fn test_Projection(_: StructWithProjection) -> StructWithProjection {
+    loop {}
+}
+
+#[repr(transparent)]
+pub enum EnumF32 {
+    Variant(F32),
+}
+
+// CHECK: define{{.*}}float @test_EnumF32(float noundef %_1)
+#[no_mangle]
+pub extern "C" fn test_EnumF32(_: EnumF32) -> EnumF32 {
+    loop {}
+}
+
+#[repr(transparent)]
+pub enum EnumF32WithZsts {
+    Variant(Zst1, F32, Zst2),
+}
+
+// CHECK: define{{.*}}float @test_EnumF32WithZsts(float noundef %_1)
+#[no_mangle]
+pub extern "C" fn test_EnumF32WithZsts(_: EnumF32WithZsts) -> EnumF32WithZsts {
+    loop {}
+}
+
+#[repr(transparent)]
+pub union UnionF32 {
+    field: F32,
+}
+
+// CHECK: define{{.*}} float @test_UnionF32(float %_1)
+#[no_mangle]
+pub extern "C" fn test_UnionF32(_: UnionF32) -> UnionF32 {
+    loop {}
+}
+
+#[repr(transparent)]
+pub union UnionF32WithZsts {
+    zst1: Zst1,
+    field: F32,
+    zst2: Zst2,
+}
+
+// CHECK: define{{.*}}float @test_UnionF32WithZsts(float %_1)
+#[no_mangle]
+pub extern "C" fn test_UnionF32WithZsts(_: UnionF32WithZsts) -> UnionF32WithZsts {
+    loop {}
+}
+
+// All that remains to be tested are aggregates. They are tested in separate files called
+// transparent-*.rs  with `only-*` or `ignore-*` directives, because the expected LLVM IR
+// function signatures vary so much that it's not reasonably possible to cover all of them with a
+// single CHECK line.
+//
+// You may be wondering why we don't just compare the return types and argument types for equality
+// with FileCheck regex captures. Well, rustc doesn't perform newtype unwrapping on newtypes
+// containing aggregates. This is OK on all ABIs we support, but because LLVM has not gotten rid of
+// pointee types yet, the IR function signature will be syntactically different (%Foo* vs
+// %FooWrapper*).
diff --git a/tests/codegen-llvm/retpoline.rs b/tests/codegen-llvm/retpoline.rs
new file mode 100644
index 00000000000..915c2c3d797
--- /dev/null
+++ b/tests/codegen-llvm/retpoline.rs
@@ -0,0 +1,27 @@
+// ignore-tidy-linelength
+// Test that the
+// `retpoline-external-thunk`, `retpoline-indirect-branches`, `retpoline-indirect-calls`
+// target features are (not) emitted when the `retpoline/retpoline-external-thunk` flag is (not) set.
+
+//@ add-core-stubs
+//@ revisions: disabled enabled_retpoline enabled_retpoline_external_thunk
+//@ needs-llvm-components: x86
+//@ compile-flags: --target x86_64-unknown-linux-gnu
+//@ [enabled_retpoline] compile-flags: -Zretpoline
+//@ [enabled_retpoline_external_thunk] compile-flags: -Zretpoline-external-thunk
+#![crate_type = "lib"]
+#![feature(no_core)]
+#![no_core]
+extern crate minicore;
+
+#[no_mangle]
+pub fn foo() {
+    // CHECK: @foo() unnamed_addr #0
+
+    // disabled-NOT: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+retpoline-external-thunk{{.*}} }
+    // disabled-NOT: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+retpoline-indirect-branches{{.*}} }
+    // disabled-NOT: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+retpoline-indirect-calls{{.*}} }
+
+    // enabled_retpoline: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+retpoline-indirect-branches,+retpoline-indirect-calls{{.*}} }
+    // enabled_retpoline_external_thunk: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+retpoline-external-thunk,+retpoline-indirect-branches,+retpoline-indirect-calls{{.*}} }
+}
diff --git a/tests/codegen-llvm/riscv-abi/call-llvm-intrinsics.rs b/tests/codegen-llvm/riscv-abi/call-llvm-intrinsics.rs
new file mode 100644
index 00000000000..e72a649a530
--- /dev/null
+++ b/tests/codegen-llvm/riscv-abi/call-llvm-intrinsics.rs
@@ -0,0 +1,30 @@
+//@ compile-flags: -C no-prepopulate-passes
+
+//@ only-riscv64
+
+#![feature(link_llvm_intrinsics)]
+#![crate_type = "lib"]
+
+struct A;
+
+impl Drop for A {
+    fn drop(&mut self) {
+        println!("A");
+    }
+}
+
+extern "C" {
+    #[link_name = "llvm.sqrt.f32"]
+    fn sqrt(x: f32) -> f32;
+}
+
+pub fn do_call() {
+    let _a = A;
+
+    unsafe {
+        // Ensure that we `call` LLVM intrinsics instead of trying to `invoke` them
+        // CHECK: store float 4.000000e+00, ptr %{{.}}, align 4
+        // CHECK: call float @llvm.sqrt.f32(float %{{.}}
+        sqrt(4.0);
+    }
+}
diff --git a/tests/codegen-llvm/riscv-abi/cast-local-large-enough.rs b/tests/codegen-llvm/riscv-abi/cast-local-large-enough.rs
new file mode 100644
index 00000000000..9d21d73b459
--- /dev/null
+++ b/tests/codegen-llvm/riscv-abi/cast-local-large-enough.rs
@@ -0,0 +1,44 @@
+//@ add-core-stubs
+//@ compile-flags: -Copt-level=0 -Cdebuginfo=0 --target riscv64gc-unknown-linux-gnu
+//@ needs-llvm-components: riscv
+
+#![feature(no_core, lang_items)]
+#![no_std]
+#![no_core]
+#![crate_type = "lib"]
+
+extern crate minicore;
+use minicore::*;
+
+#[repr(C, align(64))]
+struct Aligned(f64);
+
+#[repr(C, align(64))]
+struct AlignedPair(f32, f64);
+
+impl Copy for Aligned {}
+impl Copy for AlignedPair {}
+
+// CHECK-LABEL: define double @read_aligned
+#[unsafe(no_mangle)]
+pub extern "C" fn read_aligned(x: &Aligned) -> Aligned {
+    // CHECK: %[[TEMP:.*]] = alloca [64 x i8], align 64
+    // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 64 %[[TEMP]], ptr align 64 %[[PTR:.*]], i64 64, i1 false)
+    // CHECK-NEXT: %[[RES:.*]] = load double, ptr %[[TEMP]], align 64
+    // CHECK-NEXT: ret double %[[RES]]
+    *x
+}
+
+// CHECK-LABEL: define { float, double } @read_aligned_pair
+#[unsafe(no_mangle)]
+pub extern "C" fn read_aligned_pair(x: &AlignedPair) -> AlignedPair {
+    // CHECK: %[[TEMP:.*]] = alloca [64 x i8], align 64
+    // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 64 %[[TEMP]], ptr align 64 %[[PTR:.*]], i64 64, i1 false)
+    // CHECK-NEXT: %[[FIRST:.*]] = load float, ptr %[[TEMP]], align 64
+    // CHECK-NEXT: %[[SECOND_PTR:.*]] = getelementptr inbounds i8, ptr %[[TEMP]], i64 8
+    // CHECK-NEXT: %[[SECOND:.*]] = load double, ptr %[[SECOND_PTR]], align 8
+    // CHECK-NEXT: %[[RES1:.*]] = insertvalue { float, double } poison, float %[[FIRST]], 0
+    // CHECK-NEXT: %[[RES2:.*]] = insertvalue { float, double } %[[RES1]], double %[[SECOND]], 1
+    // CHECK-NEXT: ret { float, double } %[[RES2]]
+    *x
+}
diff --git a/tests/codegen-llvm/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs b/tests/codegen-llvm/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs
new file mode 100644
index 00000000000..df99f6969fc
--- /dev/null
+++ b/tests/codegen-llvm/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs
@@ -0,0 +1,176 @@
+//@ add-core-stubs
+//@ compile-flags: --target riscv64gc-unknown-linux-gnu -Copt-level=3 -C no-prepopulate-passes -C panic=abort
+//@ needs-llvm-components: riscv
+
+#![crate_type = "lib"]
+#![no_core]
+#![feature(no_core, lang_items)]
+#![allow(improper_ctypes)]
+
+extern crate minicore;
+use minicore::*;
+
+// CHECK: define void @f_void()
+#[no_mangle]
+pub extern "C" fn f_void() {}
+
+// CHECK: define noundef zeroext i1 @f_scalar_0(i1 noundef zeroext %a)
+#[no_mangle]
+pub extern "C" fn f_scalar_0(a: bool) -> bool {
+    a
+}
+
+// CHECK: define noundef signext i8 @f_scalar_1(i8 noundef signext %x)
+#[no_mangle]
+pub extern "C" fn f_scalar_1(x: i8) -> i8 {
+    x
+}
+
+// CHECK: define noundef zeroext i8 @f_scalar_2(i8 noundef zeroext %x)
+#[no_mangle]
+pub extern "C" fn f_scalar_2(x: u8) -> u8 {
+    x
+}
+
+// CHECK: define noundef signext i32 @f_scalar_3(i32 noundef signext %x)
+#[no_mangle]
+pub extern "C" fn f_scalar_3(x: i32) -> u32 {
+    x as u32
+}
+
+// CHECK: define noundef i64 @f_scalar_4(i64 noundef %x)
+#[no_mangle]
+pub extern "C" fn f_scalar_4(x: i64) -> i64 {
+    x
+}
+
+// CHECK: define float @f_fp_scalar_1(float %0)
+#[no_mangle]
+pub extern "C" fn f_fp_scalar_1(x: f32) -> f32 {
+    x
+}
+// CHECK: define double @f_fp_scalar_2(double %0)
+#[no_mangle]
+pub extern "C" fn f_fp_scalar_2(x: f64) -> f64 {
+    x
+}
+
+#[repr(C)]
+pub struct Empty {}
+
+// CHECK: define void @f_agg_empty_struct()
+#[no_mangle]
+pub extern "C" fn f_agg_empty_struct(e: Empty) -> Empty {
+    e
+}
+
+#[repr(C)]
+pub struct Tiny {
+    a: u16,
+    b: u16,
+    c: u16,
+    d: u16,
+}
+
+// CHECK: define void @f_agg_tiny(i64 %0)
+#[no_mangle]
+pub extern "C" fn f_agg_tiny(mut e: Tiny) {}
+
+// CHECK: define i64 @f_agg_tiny_ret()
+#[no_mangle]
+pub extern "C" fn f_agg_tiny_ret() -> Tiny {
+    Tiny { a: 1, b: 2, c: 3, d: 4 }
+}
+
+#[repr(C)]
+pub struct Small {
+    a: i64,
+    b: *mut i64,
+}
+
+// CHECK: define void @f_agg_small([2 x i64] %0)
+#[no_mangle]
+pub extern "C" fn f_agg_small(mut x: Small) {}
+
+// CHECK: define [2 x i64] @f_agg_small_ret()
+#[no_mangle]
+pub extern "C" fn f_agg_small_ret() -> Small {
+    Small { a: 1, b: 0 as *mut _ }
+}
+
+#[repr(C)]
+pub struct SmallAligned {
+    a: i128,
+}
+
+// CHECK: define void @f_agg_small_aligned(i128 %0)
+#[no_mangle]
+pub extern "C" fn f_agg_small_aligned(mut x: SmallAligned) {}
+
+#[repr(C)]
+pub struct Large {
+    a: i64,
+    b: i64,
+    c: i64,
+    d: i64,
+}
+
+// CHECK: define void @f_agg_large(ptr {{.*}}%x)
+#[no_mangle]
+pub extern "C" fn f_agg_large(mut x: Large) {}
+
+// CHECK: define void @f_agg_large_ret(ptr {{.*}}sret{{.*}}, i32 noundef signext %i, i8 noundef signext %j)
+#[no_mangle]
+pub extern "C" fn f_agg_large_ret(i: i32, j: i8) -> Large {
+    Large { a: 1, b: 2, c: 3, d: 4 }
+}
+
+// CHECK: define void @f_scalar_stack_1(i64 %0, [2 x i64] %1, i128 %2, ptr {{.*}}%d, i8 noundef zeroext %e, i8 noundef signext %f, i8 noundef %g, i8 noundef %h)
+#[no_mangle]
+pub extern "C" fn f_scalar_stack_1(
+    a: Tiny,
+    b: Small,
+    c: SmallAligned,
+    d: Large,
+    e: u8,
+    f: i8,
+    g: u8,
+    h: i8,
+) {
+}
+
+// CHECK: define void @f_scalar_stack_2(ptr {{.*}}sret{{.*}} %_0, i64 noundef %a, i128 %0, i128 %1, i64 noundef %d, i8 noundef zeroext %e, i8 noundef %f, i8 noundef %g)
+#[no_mangle]
+pub extern "C" fn f_scalar_stack_2(
+    a: u64,
+    b: SmallAligned,
+    c: SmallAligned,
+    d: u64,
+    e: u8,
+    f: i8,
+    g: u8,
+) -> Large {
+    Large { a: a as i64, b: e as i64, c: f as i64, d: g as i64 }
+}
+
+extern "C" {
+    fn f_va_callee(_: i32, ...) -> i32;
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn f_va_caller() {
+    // CHECK: call noundef signext i32 (i32, ...) @f_va_callee(i32 noundef signext 1, i32 noundef signext 2, i64 noundef 3, double {{.*}}, double {{.*}}, i64 {{.*}}, [2 x i64] {{.*}}, i128 {{.*}}, ptr {{.*}})
+    f_va_callee(
+        1,
+        2i32,
+        3i64,
+        4.0f64,
+        5.0f64,
+        Tiny { a: 1, b: 2, c: 3, d: 4 },
+        Small { a: 10, b: 0 as *mut _ },
+        SmallAligned { a: 11 },
+        Large { a: 12, b: 13, c: 14, d: 15 },
+    );
+    // CHECK: call noundef signext i32 (i32, ...) @f_va_callee(i32 noundef signext 1, i32 noundef signext 2, i32 noundef signext 3, i32 noundef signext 4, i128 {{.*}}, i32 noundef signext 6, i32 noundef signext 7, i32 noundef 8, i32 noundef 9)
+    f_va_callee(1, 2i32, 3i32, 4i32, SmallAligned { a: 5 }, 6i32, 7i32, 8i32, 9i32);
+}
diff --git a/tests/codegen-llvm/riscv-abi/riscv64-lp64d-abi.rs b/tests/codegen-llvm/riscv-abi/riscv64-lp64d-abi.rs
new file mode 100644
index 00000000000..d768ab9381a
--- /dev/null
+++ b/tests/codegen-llvm/riscv-abi/riscv64-lp64d-abi.rs
@@ -0,0 +1,299 @@
+//@ add-core-stubs
+//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes --target riscv64gc-unknown-linux-gnu
+//@ needs-llvm-components: riscv
+
+#![feature(no_core, lang_items)]
+#![crate_type = "lib"]
+#![no_std]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+// CHECK: define void @f_fpr_tracking(double %0, double %1, double %2, double %3, double %4, double %5, double %6, double %7, i8 noundef zeroext %i)
+#[no_mangle]
+pub extern "C" fn f_fpr_tracking(
+    a: f64,
+    b: f64,
+    c: f64,
+    d: f64,
+    e: f64,
+    f: f64,
+    g: f64,
+    h: f64,
+    i: u8,
+) {
+}
+
+#[repr(C)]
+pub struct Double {
+    f: f64,
+}
+
+#[repr(C)]
+pub struct DoubleDouble {
+    f: f64,
+    g: f64,
+}
+
+#[repr(C)]
+pub struct DoubleFloat {
+    f: f64,
+    g: f32,
+}
+
+// CHECK: define void @f_double_s_arg(double %0)
+#[no_mangle]
+pub extern "C" fn f_double_s_arg(a: Double) {}
+
+// CHECK: define double @f_ret_double_s()
+#[no_mangle]
+pub extern "C" fn f_ret_double_s() -> Double {
+    Double { f: 1. }
+}
+
+// CHECK: define void @f_double_double_s_arg({ double, double } %0)
+#[no_mangle]
+pub extern "C" fn f_double_double_s_arg(a: DoubleDouble) {}
+
+// CHECK: define { double, double } @f_ret_double_double_s()
+#[no_mangle]
+pub extern "C" fn f_ret_double_double_s() -> DoubleDouble {
+    DoubleDouble { f: 1., g: 2. }
+}
+
+// CHECK: define void @f_double_float_s_arg({ double, float } %0)
+#[no_mangle]
+pub extern "C" fn f_double_float_s_arg(a: DoubleFloat) {}
+
+// CHECK: define { double, float } @f_ret_double_float_s()
+#[no_mangle]
+pub extern "C" fn f_ret_double_float_s() -> DoubleFloat {
+    DoubleFloat { f: 1., g: 2. }
+}
+
+// CHECK: define void @f_double_double_s_arg_insufficient_fprs(double %0, double %1, double %2, double %3, double %4, double %5, double %6, [2 x i64] %7)
+#[no_mangle]
+pub extern "C" fn f_double_double_s_arg_insufficient_fprs(
+    a: f64,
+    b: f64,
+    c: f64,
+    d: f64,
+    e: f64,
+    f: f64,
+    g: f64,
+    h: DoubleDouble,
+) {
+}
+
+#[repr(C)]
+pub struct DoubleInt8 {
+    f: f64,
+    i: i8,
+}
+
+#[repr(C)]
+pub struct DoubleUInt8 {
+    f: f64,
+    i: u8,
+}
+
+#[repr(C)]
+pub struct DoubleInt32 {
+    f: f64,
+    i: i32,
+}
+
+#[repr(C)]
+pub struct DoubleInt64 {
+    f: f64,
+    i: i64,
+}
+
+// CHECK: define void @f_double_int8_s_arg({ double, i8 } %0)
+#[no_mangle]
+pub extern "C" fn f_double_int8_s_arg(a: DoubleInt8) {}
+
+// CHECK: define { double, i8 } @f_ret_double_int8_s()
+#[no_mangle]
+pub extern "C" fn f_ret_double_int8_s() -> DoubleInt8 {
+    DoubleInt8 { f: 1., i: 2 }
+}
+
+// CHECK: define void @f_double_int32_s_arg({ double, i32 } %0)
+#[no_mangle]
+pub extern "C" fn f_double_int32_s_arg(a: DoubleInt32) {}
+
+// CHECK: define { double, i32 } @f_ret_double_int32_s()
+#[no_mangle]
+pub extern "C" fn f_ret_double_int32_s() -> DoubleInt32 {
+    DoubleInt32 { f: 1., i: 2 }
+}
+
+// CHECK: define void @f_double_uint8_s_arg({ double, i8 } %0)
+#[no_mangle]
+pub extern "C" fn f_double_uint8_s_arg(a: DoubleUInt8) {}
+
+// CHECK: define { double, i8 } @f_ret_double_uint8_s()
+#[no_mangle]
+pub extern "C" fn f_ret_double_uint8_s() -> DoubleUInt8 {
+    DoubleUInt8 { f: 1., i: 2 }
+}
+
+// CHECK: define void @f_double_int64_s_arg({ double, i64 } %0)
+#[no_mangle]
+pub extern "C" fn f_double_int64_s_arg(a: DoubleInt64) {}
+
+// CHECK: define { double, i64 } @f_ret_double_int64_s()
+#[no_mangle]
+pub extern "C" fn f_ret_double_int64_s() -> DoubleInt64 {
+    DoubleInt64 { f: 1., i: 2 }
+}
+
+// CHECK: define void @f_double_int8_s_arg_insufficient_gprs(i32 noundef signext %a, i32 noundef signext %b, i32 noundef signext %c, i32 noundef signext %d, i32 noundef signext %e, i32 noundef signext %f, i32 noundef signext %g, i32 noundef signext %h, [2 x i64] %0)
+#[no_mangle]
+pub extern "C" fn f_double_int8_s_arg_insufficient_gprs(
+    a: i32,
+    b: i32,
+    c: i32,
+    d: i32,
+    e: i32,
+    f: i32,
+    g: i32,
+    h: i32,
+    i: DoubleInt8,
+) {
+}
+
+// CHECK: define void @f_struct_double_int8_insufficient_fprs(float %0, double %1, double %2, double %3, double %4, double %5, double %6, double %7, [2 x i64] %8)
+#[no_mangle]
+pub extern "C" fn f_struct_double_int8_insufficient_fprs(
+    a: f32,
+    b: f64,
+    c: f64,
+    d: f64,
+    e: f64,
+    f: f64,
+    g: f64,
+    h: f64,
+    i: DoubleInt8,
+) {
+}
+
+#[repr(C)]
+pub struct DoubleArr1 {
+    a: [f64; 1],
+}
+
+// CHECK: define void @f_doublearr1_s_arg(double %0)
+#[no_mangle]
+pub extern "C" fn f_doublearr1_s_arg(a: DoubleArr1) {}
+
+// CHECK: define double @f_ret_doublearr1_s()
+#[no_mangle]
+pub extern "C" fn f_ret_doublearr1_s() -> DoubleArr1 {
+    DoubleArr1 { a: [1.] }
+}
+
+#[repr(C)]
+pub struct DoubleArr2 {
+    a: [f64; 2],
+}
+
+// CHECK: define void @f_doublearr2_s_arg({ double, double } %0)
+#[no_mangle]
+pub extern "C" fn f_doublearr2_s_arg(a: DoubleArr2) {}
+
+// CHECK: define { double, double } @f_ret_doublearr2_s()
+#[no_mangle]
+pub extern "C" fn f_ret_doublearr2_s() -> DoubleArr2 {
+    DoubleArr2 { a: [1., 2.] }
+}
+
+#[repr(C)]
+pub struct Tricky1 {
+    f: [f64; 1],
+}
+
+#[repr(C)]
+pub struct DoubleArr2Tricky1 {
+    g: [Tricky1; 2],
+}
+
+// CHECK: define void @f_doublearr2_tricky1_s_arg({ double, double } %0)
+#[no_mangle]
+pub extern "C" fn f_doublearr2_tricky1_s_arg(a: DoubleArr2Tricky1) {}
+
+// CHECK: define { double, double } @f_ret_doublearr2_tricky1_s()
+#[no_mangle]
+pub extern "C" fn f_ret_doublearr2_tricky1_s() -> DoubleArr2Tricky1 {
+    DoubleArr2Tricky1 { g: [Tricky1 { f: [1.] }, Tricky1 { f: [2.] }] }
+}
+
+#[repr(C)]
+pub struct EmptyStruct {}
+
+#[repr(C)]
+pub struct DoubleArr2Tricky2 {
+    s: EmptyStruct,
+    g: [Tricky1; 2],
+}
+
+// CHECK: define void @f_doublearr2_tricky2_s_arg({ double, double } %0)
+#[no_mangle]
+pub extern "C" fn f_doublearr2_tricky2_s_arg(a: DoubleArr2Tricky2) {}
+
+// CHECK: define { double, double } @f_ret_doublearr2_tricky2_s()
+#[no_mangle]
+pub extern "C" fn f_ret_doublearr2_tricky2_s() -> DoubleArr2Tricky2 {
+    DoubleArr2Tricky2 { s: EmptyStruct {}, g: [Tricky1 { f: [1.] }, Tricky1 { f: [2.] }] }
+}
+
+#[repr(C)]
+pub struct IntDoubleInt {
+    a: i32,
+    b: f64,
+    c: i32,
+}
+
+// CHECK: define void @f_int_double_int_s_arg(ptr {{.*}} %a)
+#[no_mangle]
+pub extern "C" fn f_int_double_int_s_arg(a: IntDoubleInt) {}
+
+// CHECK: define void @f_ret_int_double_int_s(ptr {{.*}} sret([24 x i8]) align 8 {{.*}}dereferenceable(24) %_0)
+#[no_mangle]
+pub extern "C" fn f_ret_int_double_int_s() -> IntDoubleInt {
+    IntDoubleInt { a: 1, b: 2., c: 3 }
+}
+
+#[repr(C)]
+pub struct CharCharDouble {
+    a: u8,
+    b: u8,
+    c: f64,
+}
+
+// CHECK: define void @f_char_char_double_s_arg([2 x i64] %0)
+#[no_mangle]
+pub extern "C" fn f_char_char_double_s_arg(a: CharCharDouble) {}
+
+// CHECK: define [2 x i64] @f_ret_char_char_double_s()
+#[no_mangle]
+pub extern "C" fn f_ret_char_char_double_s() -> CharCharDouble {
+    CharCharDouble { a: 1, b: 2, c: 3. }
+}
+
+#[repr(C)]
+pub union DoubleU {
+    a: f64,
+}
+
+// CHECK: define void @f_double_u_arg(i64 %0)
+#[no_mangle]
+pub extern "C" fn f_double_u_arg(a: DoubleU) {}
+
+// CHECK: define i64 @f_ret_double_u()
+#[no_mangle]
+pub extern "C" fn f_ret_double_u() -> DoubleU {
+    unsafe { DoubleU { a: 1. } }
+}
diff --git a/tests/codegen-llvm/riscv-abi/riscv64-lp64f-lp64d-abi.rs b/tests/codegen-llvm/riscv-abi/riscv64-lp64f-lp64d-abi.rs
new file mode 100644
index 00000000000..361f0322690
--- /dev/null
+++ b/tests/codegen-llvm/riscv-abi/riscv64-lp64f-lp64d-abi.rs
@@ -0,0 +1,283 @@
+//@ add-core-stubs
+//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes --target riscv64gc-unknown-linux-gnu
+//@ needs-llvm-components: riscv
+
+#![feature(no_core, lang_items)]
+#![crate_type = "lib"]
+#![no_std]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+// CHECK: define void @f_fpr_tracking(float %0, float %1, float %2, float %3, float %4, float %5, float %6, float %7, i8 noundef zeroext %i)
+#[no_mangle]
+pub extern "C" fn f_fpr_tracking(
+    a: f32,
+    b: f32,
+    c: f32,
+    d: f32,
+    e: f32,
+    f: f32,
+    g: f32,
+    h: f32,
+    i: u8,
+) {
+}
+
+#[repr(C)]
+pub struct Float {
+    f: f32,
+}
+
+#[repr(C)]
+pub struct FloatFloat {
+    f: f32,
+    g: f32,
+}
+
+// CHECK: define void @f_float_s_arg(float %0)
+#[no_mangle]
+pub extern "C" fn f_float_s_arg(a: Float) {}
+
+// CHECK: define float @f_ret_float_s()
+#[no_mangle]
+pub extern "C" fn f_ret_float_s() -> Float {
+    Float { f: 1. }
+}
+
+// CHECK: define void @f_float_float_s_arg({ float, float } %0)
+#[no_mangle]
+pub extern "C" fn f_float_float_s_arg(a: FloatFloat) {}
+
+// CHECK: define { float, float } @f_ret_float_float_s()
+#[no_mangle]
+pub extern "C" fn f_ret_float_float_s() -> FloatFloat {
+    FloatFloat { f: 1., g: 2. }
+}
+
+// CHECK: define void @f_float_float_s_arg_insufficient_fprs(float %0, float %1, float %2, float %3, float %4, float %5, float %6, i64 %7)
+#[no_mangle]
+pub extern "C" fn f_float_float_s_arg_insufficient_fprs(
+    a: f32,
+    b: f32,
+    c: f32,
+    d: f32,
+    e: f32,
+    f: f32,
+    g: f32,
+    h: FloatFloat,
+) {
+}
+
+#[repr(C)]
+pub struct FloatInt8 {
+    f: f32,
+    i: i8,
+}
+
+#[repr(C)]
+pub struct FloatUInt8 {
+    f: f32,
+    i: u8,
+}
+
+#[repr(C)]
+pub struct FloatInt32 {
+    f: f32,
+    i: i32,
+}
+
+#[repr(C)]
+pub struct FloatInt64 {
+    f: f32,
+    i: i64,
+}
+
+// CHECK: define void @f_float_int8_s_arg({ float, i8 } %0)
+#[no_mangle]
+pub extern "C" fn f_float_int8_s_arg(a: FloatInt8) {}
+
+// CHECK: define { float, i8 } @f_ret_float_int8_s()
+#[no_mangle]
+pub extern "C" fn f_ret_float_int8_s() -> FloatInt8 {
+    FloatInt8 { f: 1., i: 2 }
+}
+
+// CHECK: define void @f_float_int32_s_arg({ float, i32 } %0)
+#[no_mangle]
+pub extern "C" fn f_float_int32_s_arg(a: FloatInt32) {}
+
+// CHECK: define { float, i32 } @f_ret_float_int32_s()
+#[no_mangle]
+pub extern "C" fn f_ret_float_int32_s() -> FloatInt32 {
+    FloatInt32 { f: 1., i: 2 }
+}
+
+// CHECK: define void @f_float_uint8_s_arg({ float, i8 } %0)
+#[no_mangle]
+pub extern "C" fn f_float_uint8_s_arg(a: FloatUInt8) {}
+
+// CHECK: define { float, i8 } @f_ret_float_uint8_s()
+#[no_mangle]
+pub extern "C" fn f_ret_float_uint8_s() -> FloatUInt8 {
+    FloatUInt8 { f: 1., i: 2 }
+}
+
+// CHECK: define void @f_float_int64_s_arg({ float, i64 } %0)
+#[no_mangle]
+pub extern "C" fn f_float_int64_s_arg(a: FloatInt64) {}
+
+// CHECK: define { float, i64 } @f_ret_float_int64_s()
+#[no_mangle]
+pub extern "C" fn f_ret_float_int64_s() -> FloatInt64 {
+    FloatInt64 { f: 1., i: 2 }
+}
+
+// CHECK: define void @f_float_int8_s_arg_insufficient_gprs(i32 noundef signext %a, i32 noundef signext %b, i32 noundef signext %c, i32 noundef signext %d, i32 noundef signext %e, i32 noundef signext %f, i32 noundef signext %g, i32 noundef signext %h, i64 %0)
+#[no_mangle]
+pub extern "C" fn f_float_int8_s_arg_insufficient_gprs(
+    a: i32,
+    b: i32,
+    c: i32,
+    d: i32,
+    e: i32,
+    f: i32,
+    g: i32,
+    h: i32,
+    i: FloatInt8,
+) {
+}
+
+// CHECK: define void @f_struct_float_int8_insufficient_fprs(float %0, float %1, float %2,  float %3, float %4, float %5, float %6, float %7, i64 %8)
+#[no_mangle]
+pub extern "C" fn f_struct_float_int8_insufficient_fprs(
+    a: f32,
+    b: f32,
+    c: f32,
+    d: f32,
+    e: f32,
+    f: f32,
+    g: f32,
+    h: f32,
+    i: FloatInt8,
+) {
+}
+
+#[repr(C)]
+pub struct FloatArr1 {
+    a: [f32; 1],
+}
+
+// CHECK: define void @f_floatarr1_s_arg(float %0)
+#[no_mangle]
+pub extern "C" fn f_floatarr1_s_arg(a: FloatArr1) {}
+
+// CHECK: define float @f_ret_floatarr1_s()
+#[no_mangle]
+pub extern "C" fn f_ret_floatarr1_s() -> FloatArr1 {
+    FloatArr1 { a: [1.] }
+}
+
+#[repr(C)]
+pub struct FloatArr2 {
+    a: [f32; 2],
+}
+
+// CHECK: define void @f_floatarr2_s_arg({ float, float } %0)
+#[no_mangle]
+pub extern "C" fn f_floatarr2_s_arg(a: FloatArr2) {}
+
+// CHECK: define { float, float } @f_ret_floatarr2_s()
+#[no_mangle]
+pub extern "C" fn f_ret_floatarr2_s() -> FloatArr2 {
+    FloatArr2 { a: [1., 2.] }
+}
+
+#[repr(C)]
+pub struct Tricky1 {
+    f: [f32; 1],
+}
+
+#[repr(C)]
+pub struct FloatArr2Tricky1 {
+    g: [Tricky1; 2],
+}
+
+// CHECK: define void @f_floatarr2_tricky1_s_arg({ float, float } %0)
+#[no_mangle]
+pub extern "C" fn f_floatarr2_tricky1_s_arg(a: FloatArr2Tricky1) {}
+
+// CHECK: define { float, float } @f_ret_floatarr2_tricky1_s()
+#[no_mangle]
+pub extern "C" fn f_ret_floatarr2_tricky1_s() -> FloatArr2Tricky1 {
+    FloatArr2Tricky1 { g: [Tricky1 { f: [1.] }, Tricky1 { f: [2.] }] }
+}
+
+#[repr(C)]
+pub struct EmptyStruct {}
+
+#[repr(C)]
+pub struct FloatArr2Tricky2 {
+    s: EmptyStruct,
+    g: [Tricky1; 2],
+}
+
+// CHECK: define void @f_floatarr2_tricky2_s_arg({ float, float } %0)
+#[no_mangle]
+pub extern "C" fn f_floatarr2_tricky2_s_arg(a: FloatArr2Tricky2) {}
+
+// CHECK: define { float, float } @f_ret_floatarr2_tricky2_s()
+#[no_mangle]
+pub extern "C" fn f_ret_floatarr2_tricky2_s() -> FloatArr2Tricky2 {
+    FloatArr2Tricky2 { s: EmptyStruct {}, g: [Tricky1 { f: [1.] }, Tricky1 { f: [2.] }] }
+}
+
+#[repr(C)]
+pub struct IntFloatInt {
+    a: i32,
+    b: f32,
+    c: i32,
+}
+
+// CHECK: define void @f_int_float_int_s_arg([2 x i64] %0)
+#[no_mangle]
+pub extern "C" fn f_int_float_int_s_arg(a: IntFloatInt) {}
+
+// CHECK: define [2 x i64] @f_ret_int_float_int_s()
+#[no_mangle]
+pub extern "C" fn f_ret_int_float_int_s() -> IntFloatInt {
+    IntFloatInt { a: 1, b: 2., c: 3 }
+}
+
+#[repr(C)]
+pub struct CharCharFloat {
+    a: u8,
+    b: u8,
+    c: f32,
+}
+
+// CHECK: define void @f_char_char_float_s_arg(i64 %0)
+#[no_mangle]
+pub extern "C" fn f_char_char_float_s_arg(a: CharCharFloat) {}
+
+// CHECK: define i64 @f_ret_char_char_float_s()
+#[no_mangle]
+pub extern "C" fn f_ret_char_char_float_s() -> CharCharFloat {
+    CharCharFloat { a: 1, b: 2, c: 3. }
+}
+
+#[repr(C)]
+pub union FloatU {
+    a: f32,
+}
+
+// CHECK: define void @f_float_u_arg(i64 %0)
+#[no_mangle]
+pub extern "C" fn f_float_u_arg(a: FloatU) {}
+
+// CHECK: define i64 @f_ret_float_u()
+#[no_mangle]
+pub extern "C" fn f_ret_float_u() -> FloatU {
+    unsafe { FloatU { a: 1. } }
+}
diff --git a/tests/codegen-llvm/riscv-target-abi.rs b/tests/codegen-llvm/riscv-target-abi.rs
new file mode 100644
index 00000000000..d41fcb4dd84
--- /dev/null
+++ b/tests/codegen-llvm/riscv-target-abi.rs
@@ -0,0 +1,21 @@
+//@ add-core-stubs
+//@ revisions:riscv64gc riscv32gc riscv32imac
+
+//@[riscv64gc] compile-flags: --target=riscv64gc-unknown-linux-gnu
+//@[riscv64gc] needs-llvm-components: riscv
+// riscv64gc: !{i32 1, !"target-abi", !"lp64d"}
+
+//@[riscv32gc] compile-flags: --target=riscv32gc-unknown-linux-musl
+//@[riscv32gc] needs-llvm-components: riscv
+// riscv32gc: !{i32 1, !"target-abi", !"ilp32d"}
+
+//@[riscv32imac] compile-flags: --target=riscv32imac-unknown-none-elf
+//@[riscv32imac] needs-llvm-components: riscv
+// riscv32imac: !{i32 1, !"target-abi", !"ilp32"}
+
+#![feature(no_core, lang_items)]
+#![crate_type = "lib"]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
diff --git a/tests/codegen-llvm/rust-abi-arch-specific-adjustment.rs b/tests/codegen-llvm/rust-abi-arch-specific-adjustment.rs
new file mode 100644
index 00000000000..561f081c700
--- /dev/null
+++ b/tests/codegen-llvm/rust-abi-arch-specific-adjustment.rs
@@ -0,0 +1,111 @@
+//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes
+//@ revisions: riscv64 loongarch64
+
+//@[riscv64] only-riscv64
+//@[riscv64] compile-flags: --target riscv64gc-unknown-linux-gnu
+//@[riscv64] needs-llvm-components: riscv
+
+//@[loongarch64] only-loongarch64
+//@[loongarch64] compile-flags: --target loongarch64-unknown-linux-gnu
+//@[loongarch64] needs-llvm-components: loongarch
+
+#![crate_type = "lib"]
+
+#[no_mangle]
+// riscv64:     define noundef i8 @arg_attr_u8(i8 noundef zeroext %x)
+// loongarch64: define noundef i8 @arg_attr_u8(i8 noundef zeroext %x)
+pub fn arg_attr_u8(x: u8) -> u8 {
+    x
+}
+
+#[no_mangle]
+// riscv64:     define noundef i16 @arg_attr_u16(i16 noundef zeroext %x)
+// loongarch64: define noundef i16 @arg_attr_u16(i16 noundef zeroext %x)
+pub fn arg_attr_u16(x: u16) -> u16 {
+    x
+}
+
+#[no_mangle]
+// riscv64:     define noundef i32 @arg_attr_u32(i32 noundef signext %x)
+// loongarch64: define noundef i32 @arg_attr_u32(i32 noundef signext %x)
+pub fn arg_attr_u32(x: u32) -> u32 {
+    x
+}
+
+#[no_mangle]
+// riscv64:     define noundef i64 @arg_attr_u64(i64 noundef %x)
+// loongarch64: define noundef i64 @arg_attr_u64(i64 noundef %x)
+pub fn arg_attr_u64(x: u64) -> u64 {
+    x
+}
+
+#[no_mangle]
+// riscv64:     define noundef i128 @arg_attr_u128(i128 noundef %x)
+// loongarch64: define noundef i128 @arg_attr_u128(i128 noundef %x)
+pub fn arg_attr_u128(x: u128) -> u128 {
+    x
+}
+
+#[no_mangle]
+// riscv64:     define noundef i8 @arg_attr_i8(i8 noundef signext %x)
+// loongarch64: define noundef i8 @arg_attr_i8(i8 noundef signext %x)
+pub fn arg_attr_i8(x: i8) -> i8 {
+    x
+}
+
+#[no_mangle]
+// riscv64:     define noundef i16 @arg_attr_i16(i16 noundef signext %x)
+// loongarch64: define noundef i16 @arg_attr_i16(i16 noundef signext %x)
+pub fn arg_attr_i16(x: i16) -> i16 {
+    x
+}
+
+#[no_mangle]
+// riscv64:     define noundef i32 @arg_attr_i32(i32 noundef signext %x)
+// loongarch64: define noundef i32 @arg_attr_i32(i32 noundef signext %x)
+pub fn arg_attr_i32(x: i32) -> i32 {
+    x
+}
+
+#[no_mangle]
+// riscv64:     define noundef i64 @arg_attr_i64(i64 noundef %x)
+// loongarch64: define noundef i64 @arg_attr_i64(i64 noundef %x)
+pub fn arg_attr_i64(x: i64) -> i64 {
+    x
+}
+
+#[no_mangle]
+// riscv64:     define noundef i128 @arg_attr_i128(i128 noundef %x)
+// loongarch64: define noundef i128 @arg_attr_i128(i128 noundef %x)
+pub fn arg_attr_i128(x: i128) -> i128 {
+    x
+}
+
+#[no_mangle]
+// riscv64:     define noundef zeroext i1 @arg_attr_bool(i1 noundef zeroext %x)
+// loongarch64: define noundef zeroext i1 @arg_attr_bool(i1 noundef zeroext %x)
+pub fn arg_attr_bool(x: bool) -> bool {
+    x
+}
+
+#[no_mangle]
+// ignore-tidy-linelength
+// riscv64:     define noundef{{( range\(i32 0, 1114112\))?}} i32 @arg_attr_char(i32 noundef signext{{( range\(i32 0, 1114112\))?}} %x)
+// loongarch64: define noundef{{( range\(i32 0, 1114112\))?}} i32 @arg_attr_char(i32 noundef signext{{( range\(i32 0, 1114112\))?}} %x)
+pub fn arg_attr_char(x: char) -> char {
+    x
+}
+
+#[no_mangle]
+// riscv64:     define noundef float @arg_attr_f32(float noundef %x)
+// loongarch64: define noundef float @arg_attr_f32(float noundef %x)
+pub fn arg_attr_f32(x: f32) -> f32 {
+    x
+}
+
+#[no_mangle]
+// riscv64:     define noundef double @arg_attr_f64(double noundef %x)
+// loongarch64: define noundef double @arg_attr_f64(double noundef %x)
+pub fn arg_attr_f64(x: f64) -> f64 {
+    x
+}
diff --git a/tests/codegen-llvm/s390x-simd.rs b/tests/codegen-llvm/s390x-simd.rs
new file mode 100644
index 00000000000..ac39357519e
--- /dev/null
+++ b/tests/codegen-llvm/s390x-simd.rs
@@ -0,0 +1,143 @@
+//! test that s390x vector types are passed using `PassMode::Direct`
+//! see also https://github.com/rust-lang/rust/issues/135744
+//@ add-core-stubs
+//@ compile-flags: --target s390x-unknown-linux-gnu -Copt-level=3
+//@ needs-llvm-components: systemz
+
+#![crate_type = "rlib"]
+#![feature(no_core, asm_experimental_arch)]
+#![feature(s390x_target_feature, simd_ffi, link_llvm_intrinsics, repr_simd)]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+#[repr(simd)]
+struct i8x16([i8; 16]);
+
+#[repr(simd)]
+struct i16x8([i16; 8]);
+
+#[repr(simd)]
+struct i32x4([i32; 4]);
+
+#[repr(simd)]
+struct i64x2([i64; 2]);
+
+#[repr(simd)]
+struct f32x4([f32; 4]);
+
+#[repr(simd)]
+struct f64x2([f64; 2]);
+
+#[allow(improper_ctypes)]
+extern "C" {
+    #[link_name = "llvm.smax.v16i8"]
+    fn vmxb(a: i8x16, b: i8x16) -> i8x16;
+    #[link_name = "llvm.smax.v8i16"]
+    fn vmxh(a: i16x8, b: i16x8) -> i16x8;
+    #[link_name = "llvm.smax.v4i32"]
+    fn vmxf(a: i32x4, b: i32x4) -> i32x4;
+    #[link_name = "llvm.smax.v2i64"]
+    fn vmxg(a: i64x2, b: i64x2) -> i64x2;
+}
+
+// CHECK-LABEL: define <16 x i8> @max_i8x16
+// CHECK-SAME: <16 x i8> %a, <16 x i8> %b
+// CHECK: call <16 x i8> @llvm.smax.v16i8(<16 x i8> %a, <16 x i8> %b)
+#[no_mangle]
+#[target_feature(enable = "vector")]
+pub unsafe extern "C" fn max_i8x16(a: i8x16, b: i8x16) -> i8x16 {
+    vmxb(a, b)
+}
+
+// CHECK-LABEL: define <8 x i16> @max_i16x8
+// CHECK-SAME: <8 x i16> %a, <8 x i16> %b
+// CHECK: call <8 x i16> @llvm.smax.v8i16(<8 x i16> %a, <8 x i16> %b)
+#[no_mangle]
+#[target_feature(enable = "vector")]
+pub unsafe extern "C" fn max_i16x8(a: i16x8, b: i16x8) -> i16x8 {
+    vmxh(a, b)
+}
+
+// CHECK-LABEL: define <4 x i32> @max_i32x4
+// CHECK-SAME: <4 x i32> %a, <4 x i32> %b
+// CHECK: call <4 x i32> @llvm.smax.v4i32(<4 x i32> %a, <4 x i32> %b)
+#[no_mangle]
+#[target_feature(enable = "vector")]
+pub unsafe extern "C" fn max_i32x4(a: i32x4, b: i32x4) -> i32x4 {
+    vmxf(a, b)
+}
+
+// CHECK-LABEL: define <2 x i64> @max_i64x2
+// CHECK-SAME: <2 x i64> %a, <2 x i64> %b
+// CHECK: call <2 x i64> @llvm.smax.v2i64(<2 x i64> %a, <2 x i64> %b)
+#[no_mangle]
+#[target_feature(enable = "vector")]
+pub unsafe extern "C" fn max_i64x2(a: i64x2, b: i64x2) -> i64x2 {
+    vmxg(a, b)
+}
+
+// CHECK-LABEL: define <4 x float> @choose_f32x4
+// CHECK-SAME: <4 x float> %a, <4 x float> %b
+#[no_mangle]
+#[target_feature(enable = "vector")]
+pub unsafe extern "C" fn choose_f32x4(a: f32x4, b: f32x4, c: bool) -> f32x4 {
+    if c { a } else { b }
+}
+
+// CHECK-LABEL: define <2 x double> @choose_f64x2
+// CHECK-SAME: <2 x double> %a, <2 x double> %b
+#[no_mangle]
+#[target_feature(enable = "vector")]
+pub unsafe extern "C" fn choose_f64x2(a: f64x2, b: f64x2, c: bool) -> f64x2 {
+    if c { a } else { b }
+}
+
+#[repr(C)]
+struct Wrapper<T>(T);
+
+#[no_mangle]
+#[inline(never)]
+#[target_feature(enable = "vector")]
+pub unsafe extern "C" fn max_wrapper_i8x16(a: Wrapper<i8x16>, b: Wrapper<i8x16>) -> Wrapper<i8x16> {
+    // CHECK-LABEL: max_wrapper_i8x16
+    // CHECK-SAME: sret([16 x i8])
+    // CHECK-SAME: <16 x i8>
+    // CHECK-SAME: <16 x i8>
+    // CHECK: call <16 x i8> @llvm.smax.v16i8
+    // CHECK-SAME: <16 x i8>
+    // CHECK-SAME: <16 x i8>
+    Wrapper(vmxb(a.0, b.0))
+}
+
+#[no_mangle]
+#[inline(never)]
+#[target_feature(enable = "vector")]
+pub unsafe extern "C" fn max_wrapper_i64x2(a: Wrapper<i64x2>, b: Wrapper<i64x2>) -> Wrapper<i64x2> {
+    // CHECK-LABEL: max_wrapper_i64x2
+    // CHECK-SAME: sret([16 x i8])
+    // CHECK-SAME: <16 x i8>
+    // CHECK-SAME: <16 x i8>
+    // CHECK: call <2 x i64> @llvm.smax.v2i64
+    // CHECK-SAME: <2 x i64>
+    // CHECK-SAME: <2 x i64>
+    Wrapper(vmxg(a.0, b.0))
+}
+
+#[no_mangle]
+#[inline(never)]
+#[target_feature(enable = "vector")]
+pub unsafe extern "C" fn choose_wrapper_f64x2(
+    a: Wrapper<f64x2>,
+    b: Wrapper<f64x2>,
+    c: bool,
+) -> Wrapper<f64x2> {
+    // CHECK-LABEL: choose_wrapper_f64x2
+    // CHECK-SAME: sret([16 x i8])
+    // CHECK-SAME: <16 x i8>
+    // CHECK-SAME: <16 x i8>
+    Wrapper(choose_f64x2(a.0, b.0, c))
+}
+
+// CHECK: declare <2 x i64> @llvm.smax.v2i64(<2 x i64>, <2 x i64>)
diff --git a/tests/codegen-llvm/sanitizer/aarch64-shadow-call-stack-with-fixed-x18.rs b/tests/codegen-llvm/sanitizer/aarch64-shadow-call-stack-with-fixed-x18.rs
new file mode 100644
index 00000000000..e1d7dc2d631
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/aarch64-shadow-call-stack-with-fixed-x18.rs
@@ -0,0 +1,20 @@
+//@ add-core-stubs
+//@ revisions: aarch64 android
+//@[aarch64] compile-flags: --target aarch64-unknown-none -Zfixed-x18 -Zsanitizer=shadow-call-stack
+//@[aarch64] needs-llvm-components: aarch64
+//@[android] compile-flags: --target aarch64-linux-android -Zsanitizer=shadow-call-stack
+//@[android] needs-llvm-components: aarch64
+
+#![allow(internal_features)]
+#![crate_type = "rlib"]
+#![feature(no_core, lang_items)]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+// CHECK: ; Function Attrs:{{.*}}shadowcallstack
+#[no_mangle]
+pub fn foo() {}
+
+// CHECK: attributes #0 = {{.*}}shadowcallstack{{.*}}
diff --git a/tests/codegen-llvm/sanitizer/address-sanitizer-globals-tracking.rs b/tests/codegen-llvm/sanitizer/address-sanitizer-globals-tracking.rs
new file mode 100644
index 00000000000..f319306f93f
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/address-sanitizer-globals-tracking.rs
@@ -0,0 +1,44 @@
+// Verifies that AddressSanitizer symbols show up as expected in LLVM IR with `-Zsanitizer`.
+// This is a regression test for https://github.com/rust-lang/rust/issues/113404
+//
+// Notes about the `compile-flags` below:
+//
+// * The original issue only reproed with LTO - this is why this angle has
+//   extra test coverage via different `revisions`
+// * To observe the failure/repro at LLVM-IR level we need to use `staticlib`
+//   which necessitates `-C prefer-dynamic=false` - without the latter flag,
+//   we would have run into "cannot prefer dynamic linking when performing LTO".
+//
+// The test is restricted to `only-linux`, because the sanitizer-related instrumentation is target
+// specific.  In particular, `___asan_globals_registered` is only used in the
+// `InstrumentGlobalsELF` and `InstrumentGlobalsMachO` code paths.  The `only-linux` filter is
+// narrower than really needed (i.e. narrower than ELF-or-MachO), but this seems ok - having a
+// linux-only regression test should be sufficient here.
+//
+//@ needs-sanitizer-address
+//@ only-linux
+//
+//@ revisions:ASAN ASAN-FAT-LTO
+//@                compile-flags: -Zsanitizer=address -Ctarget-feature=-crt-static
+//@[ASAN]          compile-flags:
+//@[ASAN-FAT-LTO]  compile-flags: -Cprefer-dynamic=false -Clto=fat
+
+#![crate_type = "staticlib"]
+
+// The test below mimics `CACHED_POW10` from `library/core/src/num/flt2dec/strategy/grisu.rs` which
+// (because of incorrect handling of `___asan_globals_registered` during LTO) was incorrectly
+// reported as an ODR violation in https://crbug.com/1459233#c1.  Before this bug was fixed,
+// `___asan_globals_registered` would show up as `internal global i64` rather than `common hidden
+// global i64`.  (The test expectations ignore the exact type because on `arm-android` the type
+// is `i32` rather than `i64`.)
+//
+// CHECK: @___asan_globals_registered = common hidden global
+// CHECK: @__start_asan_globals = extern_weak hidden global
+// CHECK: @__stop_asan_globals = extern_weak hidden global
+#[no_mangle]
+pub static CACHED_POW10: [(u64, i16, i16); 4] = [
+    (0xe61acf033d1a45df, -1087, -308),
+    (0xab70fe17c79ac6ca, -1060, -300),
+    (0xff77b1fcbebcdc4f, -1034, -292),
+    (0xbe5691ef416bd60c, -1007, -284),
+];
diff --git a/tests/codegen-llvm/sanitizer/cfi/add-canonical-jump-tables-flag.rs b/tests/codegen-llvm/sanitizer/cfi/add-canonical-jump-tables-flag.rs
new file mode 100644
index 00000000000..22577e2a3c4
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/add-canonical-jump-tables-flag.rs
@@ -0,0 +1,10 @@
+// Verifies that "CFI Canonical Jump Tables" module flag is added.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi
+
+#![crate_type = "lib"]
+
+pub fn foo() {}
+
+// CHECK: !{{[0-9]+}} = !{i32 4, !"CFI Canonical Jump Tables", i32 1}
diff --git a/tests/codegen-llvm/sanitizer/cfi/add-cfi-normalize-integers-flag.rs b/tests/codegen-llvm/sanitizer/cfi/add-cfi-normalize-integers-flag.rs
new file mode 100644
index 00000000000..a54a6d84a80
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/add-cfi-normalize-integers-flag.rs
@@ -0,0 +1,10 @@
+// Verifies that "cfi-normalize-integers" module flag is added.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-normalize-integers
+
+#![crate_type = "lib"]
+
+pub fn foo() {}
+
+// CHECK: !{{[0-9]+}} = !{i32 4, !"cfi-normalize-integers", i32 1}
diff --git a/tests/codegen-llvm/sanitizer/cfi/add-enable-split-lto-unit-flag.rs b/tests/codegen-llvm/sanitizer/cfi/add-enable-split-lto-unit-flag.rs
new file mode 100644
index 00000000000..283b8f26102
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/add-enable-split-lto-unit-flag.rs
@@ -0,0 +1,10 @@
+// Verifies that "EnableSplitLTOUnit" module flag is added.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi
+
+#![crate_type = "lib"]
+
+pub fn foo() {}
+
+// CHECK: !{{[0-9]+}} = !{i32 4, !"EnableSplitLTOUnit", i32 1}
diff --git a/tests/codegen-llvm/sanitizer/cfi/dbg-location-on-cfi-blocks.rs b/tests/codegen-llvm/sanitizer/cfi/dbg-location-on-cfi-blocks.rs
new file mode 100644
index 00000000000..df65960dfe0
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/dbg-location-on-cfi-blocks.rs
@@ -0,0 +1,19 @@
+// Verifies that the parent block's debug information are assigned to the inserted cfi block.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static -Cdebuginfo=1
+
+#![crate_type = "lib"]
+
+pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}foo{{.*}}!dbg !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+    // CHECK:       start:
+    // CHECK:       [[TT:%.+]] = call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"{{[[:print:]]+}}"), !dbg !{{[0-9]+}}
+    // CHECK-NEXT:  br i1 [[TT]], label %type_test.pass, label %type_test.fail, !dbg !{{[0-9]+}}
+    // CHECK:       type_test.pass:                                   ; preds = %start
+    // CHECK-NEXT:  {{%.+}} = call i32 %f(i32{{.*}} %arg), !dbg !{{[0-9]+}}
+    // CHECK:       type_test.fail:                                   ; preds = %start
+    // CHECK-NEXT:  call void @llvm.trap(), !dbg !{{[0-9]+}}
+    // CHECK-NEXT:  unreachable, !dbg !{{[0-9]+}}
+    f(arg)
+}
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-checks-attr-no-sanitize.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-checks-attr-no-sanitize.rs
new file mode 100644
index 00000000000..71ccdc8ca62
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-checks-attr-no-sanitize.rs
@@ -0,0 +1,18 @@
+// Verifies that pointer type membership tests for indirect calls are omitted.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Copt-level=0
+
+#![crate_type = "lib"]
+#![feature(no_sanitize)]
+
+#[no_sanitize(cfi)]
+pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 {
+    // CHECK-LABEL: emit_type_checks_attr_no_sanitize::foo
+    // CHECK:       Function Attrs: {{.*}}
+    // CHECK-LABEL: define{{.*}}foo{{.*}}!type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+    // CHECK:       start:
+    // CHECK-NEXT:  {{%.+}} = call i32 %f(i32{{.*}} %arg)
+    // CHECK-NEXT:  ret i32 {{%.+}}
+    f(arg)
+}
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-checks.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-checks.rs
new file mode 100644
index 00000000000..ebc66a015df
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-checks.rs
@@ -0,0 +1,19 @@
+// Verifies that pointer type membership tests for indirect calls are emitted.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Copt-level=0
+
+#![crate_type = "lib"]
+
+pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}foo{{.*}}!type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+    // CHECK:       start:
+    // CHECK:       [[TT:%.+]] = call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"{{[[:print:]]+}}")
+    // CHECK-NEXT:  br i1 [[TT]], label %type_test.pass, label %type_test.fail
+    // CHECK:       type_test.pass:
+    // CHECK-NEXT:  {{%.+}} = call i32 %f(i32{{.*}} %arg)
+    // CHECK:       type_test.fail:
+    // CHECK-NEXT:  call void @llvm.trap()
+    // CHECK-NEXT:  unreachable
+    f(arg)
+}
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-attr-cfi-encoding.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-attr-cfi-encoding.rs
new file mode 100644
index 00000000000..9bc2e42db0f
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-attr-cfi-encoding.rs
@@ -0,0 +1,73 @@
+// Verifies that user-defined CFI encoding for types are emitted.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Copt-level=0
+
+#![crate_type = "lib"]
+#![feature(cfi_encoding, extern_types)]
+
+#[cfi_encoding = "3Foo"]
+pub struct Type1(i32);
+
+extern "C" {
+    #[cfi_encoding = "3Bar"]
+    type Type2;
+}
+
+#[cfi_encoding = "3Baz"]
+#[repr(transparent)]
+pub struct Type3(i32);
+
+#[cfi_encoding = "i"]
+pub struct Type4(i32);
+
+#[cfi_encoding = "j"]
+#[repr(transparent)]
+pub struct Type5(u32);
+
+pub fn foo0(_: Type1) {}
+// CHECK: define{{.*}}foo0{{.*}}!type ![[TYPE0:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo1(_: Type1, _: Type1) {}
+// CHECK: define{{.*}}foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo2(_: Type1, _: Type1, _: Type1) {}
+// CHECK: define{{.*}}foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo3(_: *mut Type2) {}
+// CHECK: define{{.*}}foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo4(_: *mut Type2, _: *mut Type2) {}
+// CHECK: define{{.*}}foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo5(_: *mut Type2, _: *mut Type2, _: *mut Type2) {}
+// CHECK: define{{.*}}foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo6(_: *mut Type3) {}
+// CHECK: define{{.*}}foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo7(_: *mut Type3, _: *mut Type3) {}
+// CHECK: define{{.*}}foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo8(_: *mut Type3, _: *mut Type3, _: *mut Type3) {}
+// CHECK: define{{.*}}foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo9(_: Type4) {}
+// CHECK: define{{.*}}foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo10(_: Type4, _: Type4) {}
+// CHECK: define{{.*}}foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo11(_: Type4, _: Type4, _: Type4) {}
+// CHECK: define{{.*}}foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo12(_: Type5) {}
+// CHECK: define{{.*}}foo12{{.*}}!type ![[TYPE12:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo13(_: Type5, _: Type5) {}
+// CHECK: define{{.*}}foo13{{.*}}!type ![[TYPE13:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo14(_: Type5, _: Type5, _: Type5) {}
+// CHECK: define{{.*}}foo14{{.*}}!type ![[TYPE14:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+
+// CHECK: ![[TYPE0]] = !{i64 0, !"_ZTSFv3FooE"}
+// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFv3FooS_E"}
+// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFv3FooS_S_E"}
+// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvP3BarE"}
+// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvP3BarS0_E"}
+// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvP3BarS0_S0_E"}
+// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvP3BazE"}
+// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvP3BazS0_E"}
+// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvP3BazS0_S0_E"}
+// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFviE"}
+// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFviiE"}
+// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFviiiE"}
+// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvjE"}
+// CHECK: ![[TYPE13]] = !{i64 0, !"_ZTSFvjjE"}
+// CHECK: ![[TYPE14]] = !{i64 0, !"_ZTSFvjjjE"}
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-const-generics.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-const-generics.rs
new file mode 100644
index 00000000000..9048c6a1f18
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-const-generics.rs
@@ -0,0 +1,32 @@
+// Verifies that type metadata identifiers for functions are emitted correctly
+// for const generics.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Copt-level=0
+
+#![crate_type = "lib"]
+#![feature(type_alias_impl_trait)]
+
+extern crate core;
+
+pub type Type1 = impl Send;
+
+#[define_opaque(Type1)]
+pub fn foo()
+where
+    Type1: 'static,
+{
+    pub struct Foo<T, const N: usize>([T; N]);
+    let _: Type1 = Foo([0; 32]);
+}
+
+pub fn foo1(_: Type1) {}
+// CHECK: define{{.*}}4foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo2(_: Type1, _: Type1) {}
+// CHECK: define{{.*}}4foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo3(_: Type1, _: Type1, _: Type1) {}
+// CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+
+// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo3FooIu3i32Lu5usize32EEE"}
+// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo3FooIu3i32Lu5usize32EES2_E"}
+// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo3FooIu3i32Lu5usize32EES2_S2_E"}
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-drop-in-place.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-drop-in-place.rs
new file mode 100644
index 00000000000..8fec275fd06
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-drop-in-place.rs
@@ -0,0 +1,31 @@
+// Verifies that type metadata identifiers for drop functions are emitted correctly.
+//
+// Non needs_drop drop glue isn't codegen'd at all, so we don't try to check the IDs there. But we
+// do check it's not emitted which should help catch bugs if we do start generating it again in the
+// future.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: define{{.*}}4core3ptr47drop_in_place$LT$dyn$u20$core..marker..Send$GT$
+// CHECK-SAME:  {{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+// CHECK:       call i1 @llvm.type.test(ptr {{%.+}}, metadata !"_ZTSFvPu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops4drop4Dropu6regionEE")
+
+struct EmptyDrop;
+// CHECK-NOT: define{{.*}}4core3ptr{{[0-9]+}}drop_in_place$LT${{.*}}EmptyDrop$GT${{.*}}!type ![[TYPE1]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+
+struct PresentDrop;
+
+impl Drop for PresentDrop {
+    fn drop(&mut self) {}
+    // CHECK: define{{.*}}4core3ptr{{[0-9]+}}drop_in_place$LT${{.*}}PresentDrop$GT${{.*}}!type ![[TYPE1]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+}
+
+pub fn foo() {
+    let _ = Box::new(EmptyDrop) as Box<dyn Send>;
+    let _ = Box::new(PresentDrop) as Box<dyn Send>;
+}
+
+// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvPu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops4drop4Dropu6regionEE"}
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-function-types.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-function-types.rs
new file mode 100644
index 00000000000..7e60aafff68
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-function-types.rs
@@ -0,0 +1,45 @@
+// Verifies that type metadata identifiers for functions are emitted correctly
+// for function types.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static
+
+#![crate_type = "lib"]
+
+pub fn foo1(_: fn(i32) -> i32) {}
+// CHECK: define{{.*}}4foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo2(_: fn(i32) -> i32, _: fn(i32) -> i32) {}
+// CHECK: define{{.*}}4foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo3(_: fn(i32) -> i32, _: fn(i32) -> i32, _: fn(i32) -> i32) {}
+// CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo4(_: &dyn Fn(i32) -> i32) {}
+// CHECK: define{{.*}}4foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo5(_: &dyn Fn(i32) -> i32, _: &dyn Fn(i32) -> i32) {}
+// CHECK: define{{.*}}4foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo6(_: &dyn Fn(i32) -> i32, _: &dyn Fn(i32) -> i32, _: &dyn Fn(i32) -> i32) {}
+// CHECK: define{{.*}}4foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo7(_: &dyn FnMut(i32) -> i32) {}
+// CHECK: define{{.*}}4foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo8(_: &dyn FnMut(i32) -> i32, _: &dyn FnMut(i32) -> i32) {}
+// CHECK: define{{.*}}4foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo9(_: &dyn FnMut(i32) -> i32, _: &dyn FnMut(i32) -> i32, _: &dyn FnMut(i32) -> i32) {}
+// CHECK: define{{.*}}4foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo10(_: &dyn FnOnce(i32) -> i32) {}
+// CHECK: define{{.*}}5foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo11(_: &dyn FnOnce(i32) -> i32, _: &dyn FnOnce(i32) -> i32) {}
+// CHECK: define{{.*}}5foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo12(_: &dyn FnOnce(i32) -> i32, _: &dyn FnOnce(i32) -> i32, _: &dyn FnOnce(i32) -> i32) {}
+// CHECK: define{{.*}}5foo12{{.*}}!type ![[TYPE12:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+
+// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvPFu3i32S_EE"}
+// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvPFu3i32S_ES0_E"}
+// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvPFu3i32S_ES0_S0_E"}
+// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEEE"}
+// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_E"}
+// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_S5_E"}
+// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEEE"}
+// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_E"}
+// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_S5_E"}
+// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEEE"}
+// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_E"}
+// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_S5_E"}
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-lifetimes.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-lifetimes.rs
new file mode 100644
index 00000000000..36d2e8c9f25
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-lifetimes.rs
@@ -0,0 +1,29 @@
+// Verifies that type metadata identifiers for functions are emitted correctly
+// for lifetimes/regions.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Copt-level=0
+
+#![crate_type = "lib"]
+#![feature(type_alias_impl_trait)]
+
+extern crate core;
+
+pub type Type1 = impl Send;
+
+#[define_opaque(Type1)]
+pub fn foo<'a>()
+where
+    Type1: 'static,
+{
+    pub struct Foo<'a>(&'a i32);
+    pub struct Bar<'a, 'b>(&'a i32, &'b Foo<'b>);
+    let _: Type1 = Bar;
+}
+
+pub fn foo1(_: Type1) {}
+// CHECK: define{{.*}}4foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo2(_: Type1, _: Type1) {}
+// CHECK: define{{.*}}4foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo3(_: Type1, _: Type1, _: Type1) {}
+// CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-method-secondary-typeid.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-method-secondary-typeid.rs
new file mode 100644
index 00000000000..9d611777ff0
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-method-secondary-typeid.rs
@@ -0,0 +1,21 @@
+// Verifies that a secondary type metadata identifier is assigned to methods with their concrete
+// self so they can be used as function pointers.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static
+
+#![crate_type = "lib"]
+
+trait Trait1 {
+    fn foo(&self);
+}
+
+struct Type1;
+
+impl Trait1 for Type1 {
+    fn foo(&self) {}
+    // CHECK: define{{.*}}3foo{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}}
+}
+
+// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u6regionEEE"}
+// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type1EE"}
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs
new file mode 100644
index 00000000000..a8ba8db1be3
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs
@@ -0,0 +1,86 @@
+// Verifies that type metadata identifiers for functions are emitted correctly
+// for paths.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static
+
+#![crate_type = "lib"]
+#![feature(type_alias_impl_trait)]
+
+extern crate core;
+
+pub type Type1 = impl Send;
+pub type Type2 = impl Send;
+pub type Type3 = impl Send;
+pub type Type4 = impl Send;
+
+#[define_opaque(Type1, Type2, Type4)]
+pub fn foo() {
+    // Type in extern path
+    extern "C" {
+        fn bar();
+    }
+    let _: Type1 = bar;
+
+    // Type in closure path
+    || {
+        pub struct Foo;
+        let _: Type2 = Foo;
+    };
+
+    // Type in const path
+    const {
+        pub struct Foo;
+        #[define_opaque(Type3)]
+        fn bar() -> Type3 {
+            Foo
+        }
+    };
+
+    // Type in impl path
+    struct Foo;
+    impl Foo {
+        fn bar(&self) {}
+    }
+    let _: Type4 = <Foo>::bar;
+}
+
+// Force arguments to be passed by using a reference. Otherwise, they may end up PassMode::Ignore
+
+pub fn foo1(_: &Type1) {}
+// CHECK: define{{.*}}4foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo2(_: &Type1, _: &Type1) {}
+// CHECK: define{{.*}}4foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo3(_: &Type1, _: &Type1, _: &Type1) {}
+// CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo4(_: &Type2) {}
+// CHECK: define{{.*}}4foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo5(_: &Type2, _: &Type2) {}
+// CHECK: define{{.*}}4foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo6(_: &Type2, _: &Type2, _: &Type2) {}
+// CHECK: define{{.*}}4foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo7(_: &Type3) {}
+// CHECK: define{{.*}}4foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo8(_: &Type3, _: &Type3) {}
+// CHECK: define{{.*}}4foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo9(_: &Type3, _: &Type3, _: &Type3) {}
+// CHECK: define{{.*}}4foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo10(_: &Type4) {}
+// CHECK: define{{.*}}5foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo11(_: &Type4, _: &Type4) {}
+// CHECK: define{{.*}}5foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo12(_: &Type4, _: &Type4, _: &Type4) {}
+// CHECK: define{{.*}}5foo12{{.*}}!type ![[TYPE12:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+
+// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo10{{[{}][{}]}}extern{{[}][}]}}3barEE"}
+// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo10{{[{}][{}]}}extern{{[}][}]}}3barES0_E"}
+// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo10{{[{}][{}]}}extern{{[}][}]}}3barES0_S0_E"}
+// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo11{{[{}][{}]}}closure{{[}][}]}}3FooEE"}
+// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo11{{[{}][{}]}}closure{{[}][}]}}3FooES0_E"}
+// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo11{{[{}][{}]}}closure{{[}][}]}}3FooES0_S0_E"}
+// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooEE"}
+// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooES0_E"}
+// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooES0_S0_E"}
+// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo8{{[{}][{}]}}impl{{[}][}]}}3barEE"}
+// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo8{{[{}][{}]}}impl{{[}][}]}}3barES0_E"}
+// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo8{{[{}][{}]}}impl{{[}][}]}}3barES0_S0_E"}
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-pointer-types.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-pointer-types.rs
new file mode 100644
index 00000000000..d37bb740f55
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-pointer-types.rs
@@ -0,0 +1,54 @@
+// Verifies that type metadata identifiers for functions are emitted correctly
+// for pointer types.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static
+
+#![crate_type = "lib"]
+
+pub fn foo1(_: &mut i32) {}
+// CHECK: define{{.*}}4foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo2(_: &mut i32, _: &i32) {}
+// CHECK: define{{.*}}4foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo3(_: &mut i32, _: &i32, _: &i32) {}
+// CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo4(_: &i32) {}
+// CHECK: define{{.*}}4foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo5(_: &i32, _: &mut i32) {}
+// CHECK: define{{.*}}4foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo6(_: &i32, _: &mut i32, _: &mut i32) {}
+// CHECK: define{{.*}}4foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo7(_: *mut i32) {}
+// CHECK: define{{.*}}4foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo8(_: *mut i32, _: *const i32) {}
+// CHECK: define{{.*}}4foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo9(_: *mut i32, _: *const i32, _: *const i32) {}
+// CHECK: define{{.*}}4foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo10(_: *const i32) {}
+// CHECK: define{{.*}}5foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo11(_: *const i32, _: *mut i32) {}
+// CHECK: define{{.*}}5foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo12(_: *const i32, _: *mut i32, _: *mut i32) {}
+// CHECK: define{{.*}}5foo12{{.*}}!type ![[TYPE12:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo13(_: fn(i32) -> i32) {}
+// CHECK: define{{.*}}5foo13{{.*}}!type ![[TYPE13:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo14(_: fn(i32) -> i32, _: fn(i32) -> i32) {}
+// CHECK: define{{.*}}5foo14{{.*}}!type ![[TYPE14:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo15(_: fn(i32) -> i32, _: fn(i32) -> i32, _: fn(i32) -> i32) {}
+// CHECK: define{{.*}}5foo15{{.*}}!type ![[TYPE15:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+
+// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvU3mutu3refIu3i32EE"}
+// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvU3mutu3refIu3i32ES0_E"}
+// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvU3mutu3refIu3i32ES0_S0_E"}
+// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu3refIu3i32EE"}
+// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu3refIu3i32EU3mutS0_E"}
+// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvu3refIu3i32EU3mutS0_S1_E"}
+// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvPu3i32E"}
+// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvPu3i32PKS_E"}
+// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvPu3i32PKS_S2_E"}
+// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvPKu3i32E"}
+// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvPKu3i32PS_E"}
+// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvPKu3i32PS_S2_E"}
+// CHECK: ![[TYPE13]] = !{i64 0, !"_ZTSFvPFu3i32S_EE"}
+// CHECK: ![[TYPE14]] = !{i64 0, !"_ZTSFvPFu3i32S_ES0_E"}
+// CHECK: ![[TYPE15]] = !{i64 0, !"_ZTSFvPFu3i32S_ES0_S0_E"}
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-primitive-types.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-primitive-types.rs
new file mode 100644
index 00000000000..7d9e4d05872
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-primitive-types.rs
@@ -0,0 +1,190 @@
+// Verifies that type metadata identifiers for functions are emitted correctly
+// for primitive types.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static
+
+#![crate_type = "lib"]
+
+extern crate core;
+use core::ffi::*;
+
+pub fn foo1(_: ()) {}
+// CHECK: define{{.*}}4foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo2(_: (), _: c_void) {}
+// CHECK: define{{.*}}4foo2{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo3(_: (), _: c_void, _: c_void) {}
+// CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo4(_: *mut ()) {}
+// CHECK: define{{.*}}4foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo5(_: *mut (), _: *mut c_void) {}
+// CHECK: define{{.*}}4foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo6(_: *mut (), _: *mut c_void, _: *mut c_void) {}
+// CHECK: define{{.*}}4foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo7(_: *const ()) {}
+// CHECK: define{{.*}}4foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo8(_: *const (), _: *const c_void) {}
+// CHECK: define{{.*}}4foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo9(_: *const (), _: *const c_void, _: *const c_void) {}
+// CHECK: define{{.*}}4foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo10(_: bool) {}
+// CHECK: define{{.*}}5foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo11(_: bool, _: bool) {}
+// CHECK: define{{.*}}5foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo12(_: bool, _: bool, _: bool) {}
+// CHECK: define{{.*}}5foo12{{.*}}!type ![[TYPE12:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo13(_: i8) {}
+// CHECK: define{{.*}}5foo13{{.*}}!type ![[TYPE13:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo14(_: i8, _: i8) {}
+// CHECK: define{{.*}}5foo14{{.*}}!type ![[TYPE14:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo15(_: i8, _: i8, _: i8) {}
+// CHECK: define{{.*}}5foo15{{.*}}!type ![[TYPE15:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo16(_: i16) {}
+// CHECK: define{{.*}}5foo16{{.*}}!type ![[TYPE16:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo17(_: i16, _: i16) {}
+// CHECK: define{{.*}}5foo17{{.*}}!type ![[TYPE17:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo18(_: i16, _: i16, _: i16) {}
+// CHECK: define{{.*}}5foo18{{.*}}!type ![[TYPE18:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo19(_: i32) {}
+// CHECK: define{{.*}}5foo19{{.*}}!type ![[TYPE19:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo20(_: i32, _: i32) {}
+// CHECK: define{{.*}}5foo20{{.*}}!type ![[TYPE20:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo21(_: i32, _: i32, _: i32) {}
+// CHECK: define{{.*}}5foo21{{.*}}!type ![[TYPE21:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo22(_: i64) {}
+// CHECK: define{{.*}}5foo22{{.*}}!type ![[TYPE22:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo23(_: i64, _: i64) {}
+// CHECK: define{{.*}}5foo23{{.*}}!type ![[TYPE23:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo24(_: i64, _: i64, _: i64) {}
+// CHECK: define{{.*}}5foo24{{.*}}!type ![[TYPE24:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo25(_: i128) {}
+// CHECK: define{{.*}}5foo25{{.*}}!type ![[TYPE25:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo26(_: i128, _: i128) {}
+// CHECK: define{{.*}}5foo26{{.*}}!type ![[TYPE26:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo27(_: i128, _: i128, _: i128) {}
+// CHECK: define{{.*}}5foo27{{.*}}!type ![[TYPE27:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo28(_: isize) {}
+// CHECK: define{{.*}}5foo28{{.*}}!type ![[TYPE28:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo29(_: isize, _: isize) {}
+// CHECK: define{{.*}}5foo29{{.*}}!type ![[TYPE29:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo30(_: isize, _: isize, _: isize) {}
+// CHECK: define{{.*}}5foo30{{.*}}!type ![[TYPE30:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo31(_: u8) {}
+// CHECK: define{{.*}}5foo31{{.*}}!type ![[TYPE31:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo32(_: u8, _: u8) {}
+// CHECK: define{{.*}}5foo32{{.*}}!type ![[TYPE32:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo33(_: u8, _: u8, _: u8) {}
+// CHECK: define{{.*}}5foo33{{.*}}!type ![[TYPE33:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo34(_: u16) {}
+// CHECK: define{{.*}}5foo34{{.*}}!type ![[TYPE34:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo35(_: u16, _: u16) {}
+// CHECK: define{{.*}}5foo35{{.*}}!type ![[TYPE35:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo36(_: u16, _: u16, _: u16) {}
+// CHECK: define{{.*}}5foo36{{.*}}!type ![[TYPE36:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo37(_: u32) {}
+// CHECK: define{{.*}}5foo37{{.*}}!type ![[TYPE37:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo38(_: u32, _: u32) {}
+// CHECK: define{{.*}}5foo38{{.*}}!type ![[TYPE38:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo39(_: u32, _: u32, _: u32) {}
+// CHECK: define{{.*}}5foo39{{.*}}!type ![[TYPE39:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo40(_: u64) {}
+// CHECK: define{{.*}}5foo40{{.*}}!type ![[TYPE40:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo41(_: u64, _: u64) {}
+// CHECK: define{{.*}}5foo41{{.*}}!type ![[TYPE41:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo42(_: u64, _: u64, _: u64) {}
+// CHECK: define{{.*}}5foo42{{.*}}!type ![[TYPE42:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo43(_: u128) {}
+// CHECK: define{{.*}}5foo43{{.*}}!type ![[TYPE43:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo44(_: u128, _: u128) {}
+// CHECK: define{{.*}}5foo44{{.*}}!type ![[TYPE44:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo45(_: u128, _: u128, _: u128) {}
+// CHECK: define{{.*}}5foo45{{.*}}!type ![[TYPE45:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo46(_: usize) {}
+// CHECK: define{{.*}}5foo46{{.*}}!type ![[TYPE46:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo47(_: usize, _: usize) {}
+// CHECK: define{{.*}}5foo47{{.*}}!type ![[TYPE47:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo48(_: usize, _: usize, _: usize) {}
+// CHECK: define{{.*}}5foo48{{.*}}!type ![[TYPE48:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo49(_: f32) {}
+// CHECK: define{{.*}}5foo49{{.*}}!type ![[TYPE49:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo50(_: f32, _: f32) {}
+// CHECK: define{{.*}}5foo50{{.*}}!type ![[TYPE50:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo51(_: f32, _: f32, _: f32) {}
+// CHECK: define{{.*}}5foo51{{.*}}!type ![[TYPE51:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo52(_: f64) {}
+// CHECK: define{{.*}}5foo52{{.*}}!type ![[TYPE52:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo53(_: f64, _: f64) {}
+// CHECK: define{{.*}}5foo53{{.*}}!type ![[TYPE53:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo54(_: f64, _: f64, _: f64) {}
+// CHECK: define{{.*}}5foo54{{.*}}!type ![[TYPE54:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo55(_: char) {}
+// CHECK: define{{.*}}5foo55{{.*}}!type ![[TYPE55:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo56(_: char, _: char) {}
+// CHECK: define{{.*}}5foo56{{.*}}!type ![[TYPE56:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo57(_: char, _: char, _: char) {}
+// CHECK: define{{.*}}5foo57{{.*}}!type ![[TYPE57:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo58(_: &str) {}
+// CHECK: define{{.*}}5foo58{{.*}}!type ![[TYPE58:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo59(_: &str, _: &str) {}
+// CHECK: define{{.*}}5foo59{{.*}}!type ![[TYPE59:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo60(_: &str, _: &str, _: &str) {}
+// CHECK: define{{.*}}5foo60{{.*}}!type ![[TYPE60:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+
+// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvvE"}
+// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvPvE"}
+// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvPvS_E"}
+// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvPvS_S_E"}
+// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvPKvE"}
+// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvPKvS0_E"}
+// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvPKvS0_S0_E"}
+// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvbE"}
+// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvbbE"}
+// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvbbbE"}
+// CHECK: ![[TYPE13]] = !{i64 0, !"_ZTSFvu2i8E"}
+// CHECK: ![[TYPE14]] = !{i64 0, !"_ZTSFvu2i8S_E"}
+// CHECK: ![[TYPE15]] = !{i64 0, !"_ZTSFvu2i8S_S_E"}
+// CHECK: ![[TYPE16]] = !{i64 0, !"_ZTSFvu3i16E"}
+// CHECK: ![[TYPE17]] = !{i64 0, !"_ZTSFvu3i16S_E"}
+// CHECK: ![[TYPE18]] = !{i64 0, !"_ZTSFvu3i16S_S_E"}
+// CHECK: ![[TYPE19]] = !{i64 0, !"_ZTSFvu3i32E"}
+// CHECK: ![[TYPE20]] = !{i64 0, !"_ZTSFvu3i32S_E"}
+// CHECK: ![[TYPE21]] = !{i64 0, !"_ZTSFvu3i32S_S_E"}
+// CHECK: ![[TYPE22]] = !{i64 0, !"_ZTSFvu3i64E"}
+// CHECK: ![[TYPE23]] = !{i64 0, !"_ZTSFvu3i64S_E"}
+// CHECK: ![[TYPE24]] = !{i64 0, !"_ZTSFvu3i64S_S_E"}
+// CHECK: ![[TYPE25]] = !{i64 0, !"_ZTSFvu4i128E"}
+// CHECK: ![[TYPE26]] = !{i64 0, !"_ZTSFvu4i128S_E"}
+// CHECK: ![[TYPE27]] = !{i64 0, !"_ZTSFvu4i128S_S_E"}
+// CHECK: ![[TYPE28]] = !{i64 0, !"_ZTSFvu5isizeE"}
+// CHECK: ![[TYPE29]] = !{i64 0, !"_ZTSFvu5isizeS_E"}
+// CHECK: ![[TYPE30]] = !{i64 0, !"_ZTSFvu5isizeS_S_E"}
+// CHECK: ![[TYPE31]] = !{i64 0, !"_ZTSFvu2u8E"}
+// CHECK: ![[TYPE32]] = !{i64 0, !"_ZTSFvu2u8S_E"}
+// CHECK: ![[TYPE33]] = !{i64 0, !"_ZTSFvu2u8S_S_E"}
+// CHECK: ![[TYPE34]] = !{i64 0, !"_ZTSFvu3u16E"}
+// CHECK: ![[TYPE35]] = !{i64 0, !"_ZTSFvu3u16S_E"}
+// CHECK: ![[TYPE36]] = !{i64 0, !"_ZTSFvu3u16S_S_E"}
+// CHECK: ![[TYPE37]] = !{i64 0, !"_ZTSFvu3u32E"}
+// CHECK: ![[TYPE38]] = !{i64 0, !"_ZTSFvu3u32S_E"}
+// CHECK: ![[TYPE39]] = !{i64 0, !"_ZTSFvu3u32S_S_E"}
+// CHECK: ![[TYPE40]] = !{i64 0, !"_ZTSFvu3u64E"}
+// CHECK: ![[TYPE41]] = !{i64 0, !"_ZTSFvu3u64S_E"}
+// CHECK: ![[TYPE42]] = !{i64 0, !"_ZTSFvu3u64S_S_E"}
+// CHECK: ![[TYPE43]] = !{i64 0, !"_ZTSFvu4u128E"}
+// CHECK: ![[TYPE44]] = !{i64 0, !"_ZTSFvu4u128S_E"}
+// CHECK: ![[TYPE45]] = !{i64 0, !"_ZTSFvu4u128S_S_E"}
+// CHECK: ![[TYPE46]] = !{i64 0, !"_ZTSFvu5usizeE"}
+// CHECK: ![[TYPE47]] = !{i64 0, !"_ZTSFvu5usizeS_E"}
+// CHECK: ![[TYPE48]] = !{i64 0, !"_ZTSFvu5usizeS_S_E"}
+// CHECK: ![[TYPE49]] = !{i64 0, !"_ZTSFvfE"}
+// CHECK: ![[TYPE50]] = !{i64 0, !"_ZTSFvffE"}
+// CHECK: ![[TYPE51]] = !{i64 0, !"_ZTSFvfffE"}
+// CHECK: ![[TYPE52]] = !{i64 0, !"_ZTSFvdE"}
+// CHECK: ![[TYPE53]] = !{i64 0, !"_ZTSFvddE"}
+// CHECK: ![[TYPE54]] = !{i64 0, !"_ZTSFvdddE"}
+// CHECK: ![[TYPE55]] = !{i64 0, !"_ZTSFvu4charE"}
+// CHECK: ![[TYPE56]] = !{i64 0, !"_ZTSFvu4charS_E"}
+// CHECK: ![[TYPE57]] = !{i64 0, !"_ZTSFvu4charS_S_E"}
+// CHECK: ![[TYPE58]] = !{i64 0, !"_ZTSFvu3refIu3strEE"}
+// CHECK: ![[TYPE59]] = !{i64 0, !"_ZTSFvu3refIu3strES0_E"}
+// CHECK: ![[TYPE60]] = !{i64 0, !"_ZTSFvu3refIu3strES0_S0_E"}
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-repr-transparent-types.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-repr-transparent-types.rs
new file mode 100644
index 00000000000..0f97c70f3f9
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-repr-transparent-types.rs
@@ -0,0 +1,79 @@
+// Verifies that type metadata identifiers for functions are emitted correctly
+// for repr transparent types.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static
+
+#![crate_type = "lib"]
+
+extern crate core;
+use core::ffi::*;
+use std::marker::PhantomData;
+
+struct Foo(i32);
+
+// repr(transparent) user-defined type
+#[repr(transparent)]
+pub struct Type1 {
+    member1: (),
+    member2: PhantomData<i32>,
+    member3: Foo,
+}
+
+// Self-referencing repr(transparent) user-defined type
+#[repr(transparent)]
+pub struct Type2<'a> {
+    member1: (),
+    member2: PhantomData<i32>,
+    member3: &'a Type2<'a>,
+}
+
+pub struct Bar(i32);
+
+// repr(transparent) user-defined generic type
+#[repr(transparent)]
+pub struct Type3<T>(T);
+
+// repr(transparent) wrapper which engages in self-reference
+#[repr(transparent)]
+pub struct Type4(Type4Helper<Type4>);
+#[repr(transparent)]
+pub struct Type4Helper<T>(*mut T);
+
+pub fn foo1(_: Type1) {}
+// CHECK: define{{.*}}4foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo2(_: Type1, _: Type1) {}
+// CHECK: define{{.*}}4foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo3(_: Type1, _: Type1, _: Type1) {}
+// CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo4(_: Type2) {}
+// CHECK: define{{.*}}4foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo5(_: Type2, _: Type2) {}
+// CHECK: define{{.*}}4foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo6(_: Type2, _: Type2, _: Type2) {}
+// CHECK: define{{.*}}4foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo7(_: Type3<Bar>) {}
+// CHECK: define{{.*}}4foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo8(_: Type3<Bar>, _: Type3<Bar>) {}
+// CHECK: define{{.*}}4foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo9(_: Type3<Bar>, _: Type3<Bar>, _: Type3<Bar>) {}
+// CHECK: define{{.*}}4foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo10(_: Type4) {}
+// CHECK: define{{.*}}5foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo11(_: Type4, _: Type4) {}
+// CHECK: define{{.*}}5foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo12(_: Type4, _: Type4, _: Type4) {}
+// CHECK: define{{.*}}5foo12{{.*}}!type ![[TYPE12:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+
+// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}3FooE"}
+// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}3FooS_E"}
+// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}3FooS_S_E"}
+// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu3refIvEE"}
+// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu3refIvES_E"}
+// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvu3refIvES_S_E"}
+// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}3BarE"}
+// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}3BarS_E"}
+// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}3BarS_S_E"}
+// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvPu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type4E"}
+// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvPu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type4S0_E"}
+// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvPu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type4S0_S0_E"}
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-sequence-types.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-sequence-types.rs
new file mode 100644
index 00000000000..bdee3f47a83
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-sequence-types.rs
@@ -0,0 +1,36 @@
+// Verifies that type metadata identifiers for functions are emitted correctly
+// for sequence types.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static
+
+#![crate_type = "lib"]
+
+pub fn foo1(_: (i32, i32)) {}
+// CHECK: define{{.*}}4foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo2(_: (i32, i32), _: (i32, i32)) {}
+// CHECK: define{{.*}}4foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo3(_: (i32, i32), _: (i32, i32), _: (i32, i32)) {}
+// CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo4(_: [i32; 32]) {}
+// CHECK: define{{.*}}4foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo5(_: [i32; 32], _: [i32; 32]) {}
+// CHECK: define{{.*}}4foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo6(_: [i32; 32], _: [i32; 32], _: [i32; 32]) {}
+// CHECK: define{{.*}}4foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo7(_: &[i32]) {}
+// CHECK: define{{.*}}4foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo8(_: &[i32], _: &[i32]) {}
+// CHECK: define{{.*}}4foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo9(_: &[i32], _: &[i32], _: &[i32]) {}
+// CHECK: define{{.*}}4foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+
+// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu5tupleIu3i32S_EE"}
+// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu5tupleIu3i32S_ES0_E"}
+// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvu5tupleIu3i32S_ES0_S0_E"}
+// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvA32u3i32E"}
+// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvA32u3i32S0_E"}
+// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvA32u3i32S0_S0_E"}
+// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvu3refIu5sliceIu3i32EEE"}
+// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvu3refIu5sliceIu3i32EES1_E"}
+// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu3refIu5sliceIu3i32EES1_S1_E"}
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-trait-types.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-trait-types.rs
new file mode 100644
index 00000000000..55e816178f8
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-trait-types.rs
@@ -0,0 +1,175 @@
+// Verifies that type metadata identifiers for functions are emitted correctly
+// for trait types.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static
+
+#![crate_type = "lib"]
+
+extern crate core;
+
+pub trait Trait1 {
+    fn foo(&self);
+}
+
+#[derive(Clone, Copy)]
+pub struct Type1;
+
+impl Trait1 for Type1 {
+    fn foo(&self) {}
+}
+
+pub trait Trait2<T> {
+    fn bar(&self);
+}
+
+pub struct Type2;
+
+impl Trait2<i32> for Type2 {
+    fn bar(&self) {}
+}
+
+pub trait Trait3<T> {
+    fn baz(&self, _: &T);
+}
+
+pub struct Type3;
+
+impl<T, U> Trait3<U> for T {
+    fn baz(&self, _: &U) {}
+}
+
+pub trait Trait4<'a, T> {
+    type Output: 'a;
+    fn qux(&self, _: &T) -> Self::Output;
+}
+
+pub struct Type4;
+
+impl<'a, T, U> Trait4<'a, U> for T {
+    type Output = &'a i32;
+    fn qux(&self, _: &U) -> Self::Output {
+        &0
+    }
+}
+
+pub trait Trait5<T, const N: usize> {
+    fn quux(&self, _: &[T; N]);
+}
+
+#[derive(Copy, Clone)]
+pub struct Type5;
+
+impl<T, U, const N: usize> Trait5<U, N> for T {
+    fn quux(&self, _: &[U; N]) {}
+}
+
+pub fn foo1(_: &dyn Send) {}
+// CHECK: define{{.*}}4foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo2(_: &dyn Send, _: &dyn Send) {}
+// CHECK: define{{.*}}4foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo3(_: &dyn Send, _: &dyn Send, _: &dyn Send) {}
+// CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo4(_: &(dyn Send + Sync)) {}
+// CHECK: define{{.*}}4foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo5(_: &(dyn Send + Sync), _: &(dyn Sync + Send)) {}
+// CHECK: define{{.*}}4foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo6(_: &(dyn Send + Sync), _: &(dyn Sync + Send), _: &(dyn Sync + Send)) {}
+// CHECK: define{{.*}}4foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo7(_: &(dyn Trait1 + Send)) {}
+// CHECK: define{{.*}}4foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo8(_: &(dyn Trait1 + Send), _: &(dyn Trait1 + Send)) {}
+// CHECK: define{{.*}}4foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo9(_: &(dyn Trait1 + Send), _: &(dyn Trait1 + Send), _: &(dyn Trait1 + Send)) {}
+// CHECK: define{{.*}}4foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo10(_: &(dyn Trait1 + Send + Sync)) {}
+// CHECK: define{{.*}}5foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo11(_: &(dyn Trait1 + Send + Sync), _: &(dyn Trait1 + Sync + Send)) {}
+// CHECK: define{{.*}}5foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo12(
+    _: &(dyn Trait1 + Send + Sync),
+    _: &(dyn Trait1 + Sync + Send),
+    _: &(dyn Trait1 + Sync + Send),
+) {
+}
+// CHECK: define{{.*}}5foo12{{.*}}!type ![[TYPE12:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo13(_: &dyn Trait1) {}
+// CHECK: define{{.*}}5foo13{{.*}}!type ![[TYPE13:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo14(_: &dyn Trait1, _: &dyn Trait1) {}
+// CHECK: define{{.*}}5foo14{{.*}}!type ![[TYPE14:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo15(_: &dyn Trait1, _: &dyn Trait1, _: &dyn Trait1) {}
+// CHECK: define{{.*}}5foo15{{.*}}!type ![[TYPE15:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo16<T>(_: &dyn Trait2<T>) {}
+pub fn bar16() {
+    let a = Type2;
+    foo16(&a);
+}
+// CHECK: define{{.*}}5foo16{{.*}}!type ![[TYPE16:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo17<T>(_: &dyn Trait2<T>, _: &dyn Trait2<T>) {}
+pub fn bar17() {
+    let a = Type2;
+    foo17(&a, &a);
+}
+// CHECK: define{{.*}}5foo17{{.*}}!type ![[TYPE17:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo18<T>(_: &dyn Trait2<T>, _: &dyn Trait2<T>, _: &dyn Trait2<T>) {}
+pub fn bar18() {
+    let a = Type2;
+    foo18(&a, &a, &a);
+}
+// CHECK: define{{.*}}5foo18{{.*}}!type ![[TYPE18:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo19(_: &dyn Trait3<Type3>) {}
+// CHECK: define{{.*}}5foo19{{.*}}!type ![[TYPE19:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo20(_: &dyn Trait3<Type3>, _: &dyn Trait3<Type3>) {}
+// CHECK: define{{.*}}5foo20{{.*}}!type ![[TYPE20:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo21(_: &dyn Trait3<Type3>, _: &dyn Trait3<Type3>, _: &dyn Trait3<Type3>) {}
+// CHECK: define{{.*}}5foo21{{.*}}!type ![[TYPE21:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo22<'a>(_: &dyn Trait4<'a, Type4, Output = &'a i32>) {}
+// CHECK: define{{.*}}5foo22{{.*}}!type ![[TYPE22:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo23<'a>(
+    _: &dyn Trait4<'a, Type4, Output = &'a i32>,
+    _: &dyn Trait4<'a, Type4, Output = &'a i32>,
+) {
+}
+// CHECK: define{{.*}}5foo23{{.*}}!type ![[TYPE23:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo24<'a>(
+    _: &dyn Trait4<'a, Type4, Output = &'a i32>,
+    _: &dyn Trait4<'a, Type4, Output = &'a i32>,
+    _: &dyn Trait4<'a, Type4, Output = &'a i32>,
+) {
+}
+// CHECK: define{{.*}}5foo24{{.*}}!type ![[TYPE24:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo25(_: &dyn Trait5<Type5, 32>) {}
+// CHECK: define{{.*}}5foo25{{.*}}!type ![[TYPE25:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo26(_: &dyn Trait5<Type5, 32>, _: &dyn Trait5<Type5, 32>) {}
+// CHECK: define{{.*}}5foo26{{.*}}!type ![[TYPE26:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo27(_: &dyn Trait5<Type5, 32>, _: &dyn Trait5<Type5, 32>, _: &dyn Trait5<Type5, 32>) {}
+// CHECK: define{{.*}}5foo27{{.*}}!type ![[TYPE27:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+
+// CHECK: ![[TYPE13]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u6regionEEE"}
+// CHECK: ![[TYPE16]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait2Iu3i32Eu6regionEEE"}
+// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEEE"}
+// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEES2_E"}
+// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEES2_S2_E"}
+// FIXME(rcvalle): Enforce autotraits ordering when encoding (e.g., alphabetical order)
+// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u6regionEEE"}
+// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u6regionEES3_E"}
+// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u6regionEES3_S3_E"}
+// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEEE"}
+// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEES3_E"}
+// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEES3_S3_E"}
+// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u6regionEEE"}
+// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u6regionEES4_E"}
+// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u6regionEES4_S4_E"}
+// CHECK: ![[TYPE14]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u6regionEES2_E"}
+// CHECK: ![[TYPE15]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u6regionEES2_S2_E"}
+// CHECK: ![[TYPE17]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait2Iu3i32Eu6regionEES3_E"}
+// CHECK: ![[TYPE18]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait2Iu3i32Eu6regionEES3_S3_E"}
+// CHECK: ![[TYPE19]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait3Iu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type3Eu6regionEEE"}
+// CHECK: ![[TYPE20]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait3Iu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type3Eu6regionEES3_E"}
+// CHECK: ![[TYPE21]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait3Iu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type3Eu6regionEES3_S3_E"}
+// CHECK: ![[TYPE22]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait4Iu6regionu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type4Eu{{[0-9]+}}NtNtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait46OutputIS_S0_Eu3refIu3i32ES_EEE"}
+// CHECK: ![[TYPE23]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait4Iu6regionu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type4Eu{{[0-9]+}}NtNtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait46OutputIS_S0_Eu3refIu3i32ES_EES6_E"}
+// CHECK: ![[TYPE24]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait4Iu6regionu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type4Eu{{[0-9]+}}NtNtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait46OutputIS_S0_Eu3refIu3i32ES_EES6_S6_E"}
+// CHECK: ![[TYPE25]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait5Iu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type5Lu5usize32EEu6regionEEE"}
+// CHECK: ![[TYPE26]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait5Iu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type5Lu5usize32EEu6regionEES5_E"}
+// CHECK: ![[TYPE27]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait5Iu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type5Lu5usize32EEu6regionEES5_S5_E"}
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-user-defined-types.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-user-defined-types.rs
new file mode 100644
index 00000000000..c1f3ca61afe
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-user-defined-types.rs
@@ -0,0 +1,62 @@
+// Verifies that type metadata identifiers for functions are emitted correctly
+// for user-defined types.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static
+
+#![crate_type = "lib"]
+#![feature(extern_types)]
+
+pub struct Struct1<T> {
+    member1: T,
+}
+
+pub enum Enum1<T> {
+    Variant1(T),
+}
+
+pub union Union1<T> {
+    member1: std::mem::ManuallyDrop<T>,
+}
+
+extern "C" {
+    pub type type1;
+}
+
+pub fn foo1(_: &Struct1<i32>) {}
+// CHECK: define{{.*}}4foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo2(_: &Struct1<i32>, _: &Struct1<i32>) {}
+// CHECK: define{{.*}}4foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo3(_: &Struct1<i32>, _: &Struct1<i32>, _: &Struct1<i32>) {}
+// CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo4(_: &Enum1<i32>) {}
+// CHECK: define{{.*}}4foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo5(_: &Enum1<i32>, _: &Enum1<i32>) {}
+// CHECK: define{{.*}}4foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo6(_: &Enum1<i32>, _: &Enum1<i32>, _: &Enum1<i32>) {}
+// CHECK: define{{.*}}4foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo7(_: &Union1<i32>) {}
+// CHECK: define{{.*}}4foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo8(_: &Union1<i32>, _: &Union1<i32>) {}
+// CHECK: define{{.*}}4foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo9(_: &Union1<i32>, _: &Union1<i32>, _: &Union1<i32>) {}
+// CHECK: define{{.*}}4foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo10(_: *mut type1) {}
+// CHECK: define{{.*}}5foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo11(_: *mut type1, _: *mut type1) {}
+// CHECK: define{{.*}}5foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo12(_: *mut type1, _: *mut type1, _: *mut type1) {}
+// CHECK: define{{.*}}5foo12{{.*}}!type ![[TYPE12:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+
+// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}7Struct1Iu3i32EEE"}
+// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}7Struct1Iu3i32EES1_E"}
+// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}7Struct1Iu3i32EES1_S1_E"}
+// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Enum1Iu3i32EEE"}
+// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Enum1Iu3i32EES1_E"}
+// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Enum1Iu3i32EES1_S1_E"}
+// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Union1Iu3i32EEE"}
+// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Union1Iu3i32EES1_E"}
+// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Union1Iu3i32EES1_S1_E"}
+// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvP5type1E"}
+// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvP5type1S0_E"}
+// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvP5type1S0_S0_E"}
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-generalized.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-generalized.rs
new file mode 100644
index 00000000000..32637b64b3e
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-generalized.rs
@@ -0,0 +1,31 @@
+// Verifies that generalized type metadata for functions are emitted.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-generalize-pointers
+
+#![crate_type = "lib"]
+
+pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}foo
+    // CHECK-SAME:  {{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}}
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_E.generalized")
+    f(arg)
+}
+
+pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}bar
+    // CHECK-SAME:  {{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}}
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_S_E.generalized")
+    f(arg1, arg2)
+}
+
+pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}baz
+    // CHECK-SAME:  {{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}}
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_S_S_E.generalized")
+    f(arg1, arg2, arg3)
+}
+
+// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFu3i32PKvS_E.generalized"}
+// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFu3i32PKvS_S_E.generalized"}
+// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFu3i32PKvS_S_S_E.generalized"}
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized-generalized.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized-generalized.rs
new file mode 100644
index 00000000000..51121b0aef1
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized-generalized.rs
@@ -0,0 +1,31 @@
+// Verifies that normalized and generalized type metadata for functions are emitted.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-normalize-integers -Zsanitizer-cfi-generalize-pointers
+
+#![crate_type = "lib"]
+
+pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}foo
+    // CHECK-SAME:  {{.*}}![[TYPE1:[0-9]+]]
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_E.normalized.generalized")
+    f(arg)
+}
+
+pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}bar
+    // CHECK-SAME:  {{.*}}![[TYPE2:[0-9]+]]
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_S_E.normalized.generalized")
+    f(arg1, arg2)
+}
+
+pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}baz
+    // CHECK-SAME:  {{.*}}![[TYPE3:[0-9]+]]
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_S_S_E.normalized.generalized")
+    f(arg1, arg2, arg3)
+}
+
+// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFu3i32PKvS_E.normalized.generalized"}
+// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFu3i32PKvS_S_E.normalized.generalized"}
+// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFu3i32PKvS_S_S_E.normalized.generalized"}
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized.rs
new file mode 100644
index 00000000000..1cfdd23006e
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized.rs
@@ -0,0 +1,31 @@
+// Verifies that normalized type metadata for functions are emitted.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-normalize-integers
+
+#![crate_type = "lib"]
+
+pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}foo
+    // CHECK-SAME:  {{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}}
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_E.normalized")
+    f(arg)
+}
+
+pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}bar
+    // CHECK-SAME:  {{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}}
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_S_E.normalized")
+    f(arg1, arg2)
+}
+
+pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}baz
+    // CHECK-SAME:  {{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}}
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_S_S_E.normalized")
+    f(arg1, arg2, arg3)
+}
+
+// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFu3i32PFS_S_ES_E.normalized"}
+// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFu3i32PFS_S_S_ES_S_E.normalized"}
+// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFu3i32PFS_S_S_S_ES_S_S_E.normalized"}
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi.rs
new file mode 100644
index 00000000000..56ab1ce4b35
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi.rs
@@ -0,0 +1,31 @@
+// Verifies that type metadata for functions are emitted.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi
+
+#![crate_type = "lib"]
+
+pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}foo
+    // CHECK-SAME:  {{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_E")
+    f(arg)
+}
+
+pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}bar
+    // CHECK-SAME:  {{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_S_E")
+    f(arg1, arg2)
+}
+
+pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}baz
+    // CHECK-SAME:  {{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_S_S_E")
+    f(arg1, arg2, arg3)
+}
+
+// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFu3i32PFS_S_ES_E"}
+// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFu3i32PFS_S_S_ES_S_E"}
+// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFu3i32PFS_S_S_S_ES_S_S_E"}
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-trait-objects.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-trait-objects.rs
new file mode 100644
index 00000000000..0e57ce322d1
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-trait-objects.rs
@@ -0,0 +1,145 @@
+// Verifies that type metadata identifiers for trait objects are emitted correctly.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Ctarget-feature=-crt-static -Zsanitizer=cfi
+
+#![crate_type = "lib"]
+
+pub trait Trait1 {
+    fn foo(&self);
+}
+
+#[derive(Clone, Copy)]
+pub struct Type1;
+
+impl Trait1 for Type1 {
+    fn foo(&self) {}
+}
+
+pub trait Trait2<T> {
+    fn bar(&self);
+}
+
+pub struct Type2;
+
+impl Trait2<i32> for Type2 {
+    fn bar(&self) {}
+}
+
+pub trait Trait3<T> {
+    fn baz(&self, _: &T);
+}
+
+pub struct Type3;
+
+impl<T, U> Trait3<U> for T {
+    fn baz(&self, _: &U) {}
+}
+
+pub trait Trait4<'a, T> {
+    type Output: 'a;
+    fn qux(&self, _: &T) -> Self::Output;
+}
+
+pub struct Type4;
+
+impl<'a, T, U> Trait4<'a, U> for T {
+    type Output = &'a i32;
+    fn qux(&self, _: &U) -> Self::Output {
+        &0
+    }
+}
+
+pub trait Trait5<T, const N: usize> {
+    fn quux(&self, _: &[T; N]);
+}
+
+#[derive(Copy, Clone)]
+pub struct Type5;
+
+impl<T, U, const N: usize> Trait5<U, N> for T {
+    fn quux(&self, _: &[U; N]) {}
+}
+
+pub fn foo1(a: &dyn Trait1) {
+    a.foo();
+    // CHECK-LABEL: define{{.*}}4foo1{{.*}}!type !{{[0-9]+}}
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%[0-9]}}, metadata !"[[TYPE1:[[:print:]]+]]")
+}
+
+pub fn bar1() {
+    let a = Type1;
+    let b = &a as &dyn Trait1;
+    b.foo();
+    // CHECK-LABEL: define{{.*}}4bar1{{.*}}!type !{{[0-9]+}}
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%[0-9]}}, metadata !"[[TYPE2:[[:print:]]+]]")
+}
+
+pub fn foo2<T>(a: &dyn Trait2<T>) {
+    a.bar();
+    // CHECK-LABEL: define{{.*}}4foo2{{.*}}!type !{{[0-9]+}}
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%[0-9]}}, metadata !"[[TYPE2:[[:print:]]+]]")
+}
+
+pub fn bar2() {
+    let a = Type2;
+    foo2(&a);
+    let b = &a as &dyn Trait2<i32>;
+    b.bar();
+    // CHECK-LABEL: define{{.*}}4bar2{{.*}}!type !{{[0-9]+}}
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%[0-9]}}, metadata !"[[TYPE2:[[:print:]]+]]")
+}
+
+pub fn foo3(a: &dyn Trait3<Type3>) {
+    let b = Type3;
+    a.baz(&b);
+    // CHECK-LABEL: define{{.*}}4foo3{{.*}}!type !{{[0-9]+}}
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%[0-9]}}, metadata !"[[TYPE3:[[:print:]]+]]")
+}
+
+pub fn bar3() {
+    let a = Type3;
+    foo3(&a);
+    let b = &a as &dyn Trait3<Type3>;
+    b.baz(&a);
+    // CHECK-LABEL: define{{.*}}4bar3{{.*}}!type !{{[0-9]+}}
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%[0-9]}}, metadata !"[[TYPE3:[[:print:]]+]]")
+}
+
+pub fn foo4<'a>(a: &dyn Trait4<'a, Type4, Output = &'a i32>) {
+    let b = Type4;
+    a.qux(&b);
+    // CHECK-LABEL: define{{.*}}4foo4{{.*}}!type !{{[0-9]+}}
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%[0-9]}}, metadata !"[[TYPE4:[[:print:]]+]]")
+}
+
+pub fn bar4<'a>() {
+    let a = Type4;
+    foo4(&a);
+    let b = &a as &dyn Trait4<'a, Type4, Output = &'a i32>;
+    b.qux(&a);
+    // CHECK-LABEL: define{{.*}}4bar4{{.*}}!type !{{[0-9]+}}
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%[0-9]}}, metadata !"[[TYPE4:[[:print:]]+]]")
+}
+
+pub fn foo5(a: &dyn Trait5<Type5, 32>) {
+    let b = &[Type5; 32];
+    a.quux(&b);
+    // CHECK-LABEL: define{{.*}}4foo5{{.*}}!type !{{[0-9]+}}
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%[0-9]}}, metadata !"[[TYPE5:[[:print:]]+]]")
+}
+
+pub fn bar5() {
+    let a = &[Type5; 32];
+    foo5(&a);
+    let b = &a as &dyn Trait5<Type5, 32>;
+    b.quux(&a);
+    // CHECK-LABEL: define{{.*}}4bar5{{.*}}!type !{{[0-9]+}}
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%[0-9]}}, metadata !"[[TYPE5:[[:print:]]+]]")
+}
+
+// CHECK: !{{[0-9]+}} = !{i64 0, !"[[TYPE1]]"}
+// CHECK: !{{[0-9]+}} = !{i64 0, !"[[TYPE2]]"}
+// CHECK: !{{[0-9]+}} = !{i64 0, !"[[TYPE3]]"}
+// CHECK: !{{[0-9]+}} = !{i64 0, !"[[TYPE4]]"}
+// CHECK: !{{[0-9]+}} = !{i64 0, !"[[TYPE5]]"}
diff --git a/tests/codegen-llvm/sanitizer/cfi/external_weak_symbols.rs b/tests/codegen-llvm/sanitizer/cfi/external_weak_symbols.rs
new file mode 100644
index 00000000000..00e9b5029af
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/external_weak_symbols.rs
@@ -0,0 +1,24 @@
+// Verifies that type metadata identifiers for for weakly-linked symbols are
+// emitted correctly.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clinker-plugin-lto -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static
+#![crate_type = "bin"]
+#![feature(linkage)]
+
+unsafe extern "C" {
+    #[linkage = "extern_weak"]
+    static FOO: Option<unsafe extern "C" fn(f64) -> ()>;
+}
+// CHECK: @_rust_extern_with_linkage_FOO = internal global ptr @FOO
+
+fn main() {
+    unsafe {
+        if let Some(method) = FOO {
+            method(4.2);
+            // CHECK: call i1 @llvm.type.test(ptr {{%method|%0}}, metadata !"_ZTSFvdE")
+        }
+    }
+}
+
+// CHECK: declare !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} extern_weak void @FOO(double) unnamed_addr #{{[0-9]+}}
diff --git a/tests/codegen-llvm/sanitizer/cfi/generalize-pointers.rs b/tests/codegen-llvm/sanitizer/cfi/generalize-pointers.rs
new file mode 100644
index 00000000000..57004da6f8e
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/generalize-pointers.rs
@@ -0,0 +1,46 @@
+// Verifies that pointer types are generalized.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-generalize-pointers -Copt-level=0
+
+#![crate_type = "lib"]
+
+extern crate core;
+
+pub fn foo0(_: &mut i32) {}
+// CHECK: define{{.*}}foo0{{.*}}!type ![[TYPE0:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo1(_: &mut i32, _: &mut i32) {}
+// CHECK: define{{.*}}foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo2(_: &mut i32, _: &mut i32, _: &mut i32) {}
+// CHECK: define{{.*}}foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo3(_: &i32) {}
+// CHECK: define{{.*}}foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo4(_: &i32, _: &i32) {}
+// CHECK: define{{.*}}foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo5(_: &i32, _: &i32, _: &i32) {}
+// CHECK: define{{.*}}foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo6(_: *mut i32) {}
+// CHECK: define{{.*}}foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo7(_: *mut i32, _: *mut i32) {}
+// CHECK: define{{.*}}foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo8(_: *mut i32, _: *mut i32, _: *mut i32) {}
+// CHECK: define{{.*}}foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo9(_: *const i32) {}
+// CHECK: define{{.*}}foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo10(_: *const i32, _: *const i32) {}
+// CHECK: define{{.*}}foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo11(_: *const i32, _: *const i32, _: *const i32) {}
+// CHECK: define{{.*}}foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}}
+
+// CHECK: ![[TYPE0]] = !{i64 0, !"_ZTSFvU3mutu3refIvEE.generalized"}
+// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvU3mutu3refIvES0_E.generalized"}
+// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvU3mutu3refIvES0_S0_E.generalized"}
+// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvu3refIvEE.generalized"}
+// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu3refIvES_E.generalized"}
+// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu3refIvES_S_E.generalized"}
+// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvPvE.generalized"}
+// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvPvS_E.generalized"}
+// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvPvS_S_E.generalized"}
+// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvPKvE.generalized"}
+// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvPKvS0_E.generalized"}
+// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvPKvS0_S0_E.generalized"}
diff --git a/tests/codegen-llvm/sanitizer/cfi/normalize-integers.rs b/tests/codegen-llvm/sanitizer/cfi/normalize-integers.rs
new file mode 100644
index 00000000000..770ee4e64e0
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/normalize-integers.rs
@@ -0,0 +1,46 @@
+// Verifies that integer types are normalized.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-normalize-integers -Copt-level=0
+
+#![crate_type = "lib"]
+
+extern crate core;
+
+pub fn foo0(_: bool) {}
+// CHECK: define{{.*}}foo0{{.*}}!type ![[TYPE0:[0-9]+]] !type !{{[0-9]+}}
+pub fn foo1(_: bool, _: bool) {}
+// CHECK: define{{.*}}foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}}
+pub fn foo2(_: bool, _: bool, _: bool) {}
+// CHECK: define{{.*}}foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}}
+pub fn foo3(_: char) {}
+// CHECK: define{{.*}}foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}}
+pub fn foo4(_: char, _: char) {}
+// CHECK: define{{.*}}foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}}
+pub fn foo5(_: char, _: char, _: char) {}
+// CHECK: define{{.*}}foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}}
+pub fn foo6(_: isize) {}
+// CHECK: define{{.*}}foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}}
+pub fn foo7(_: isize, _: isize) {}
+// CHECK: define{{.*}}foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}}
+pub fn foo8(_: isize, _: isize, _: isize) {}
+// CHECK: define{{.*}}foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}}
+pub fn foo9(_: (), _: usize) {}
+// CHECK: define{{.*}}foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}}
+pub fn foo10(_: (), _: usize, _: usize) {}
+// CHECK: define{{.*}}foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}}
+pub fn foo11(_: (), _: usize, _: usize, _: usize) {}
+// CHECK: define{{.*}}foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}}
+
+// CHECK: ![[TYPE0]] = !{i64 0, !"_ZTSFvu2u8E.normalized"}
+// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu2u8S_E.normalized"}
+// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu2u8S_S_E.normalized"}
+// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvu3u32E.normalized"}
+// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu3u32S_E.normalized"}
+// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu3u32S_S_E.normalized"}
+// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFv{{u3i16|u3i32|u3i64|u4i128}}E.normalized"}
+// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFv{{u3i16|u3i32|u3i64|u4i128}}S_E.normalized"}
+// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFv{{u3i16|u3i32|u3i64|u4i128}}S_S_E.normalized"}
+// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFv{{u3u16|u3u32|u3u64|u4u128}}E.normalized"}
+// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFv{{u3u16|u3u32|u3u64|u4u128}}S_E.normalized"}
+// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFv{{u3u16|u3u32|u3u64|u4u128}}S_S_E.normalized"}
diff --git a/tests/codegen-llvm/sanitizer/dataflow-instrument-functions.rs b/tests/codegen-llvm/sanitizer/dataflow-instrument-functions.rs
new file mode 100644
index 00000000000..a2d0d63cc17
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/dataflow-instrument-functions.rs
@@ -0,0 +1,9 @@
+// Verifies that functions are instrumented.
+//
+//@ needs-sanitizer-dataflow
+//@ compile-flags: -Copt-level=0 -Zsanitizer=dataflow
+
+#![crate_type = "lib"]
+
+pub fn foo() {}
+// CHECK: define{{.*}}foo{{.*}}.dfsan
diff --git a/tests/codegen-llvm/sanitizer/kasan-emits-instrumentation.rs b/tests/codegen-llvm/sanitizer/kasan-emits-instrumentation.rs
new file mode 100644
index 00000000000..774c9ab53f1
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/kasan-emits-instrumentation.rs
@@ -0,0 +1,41 @@
+// Verifies that `-Zsanitizer=kernel-address` emits sanitizer instrumentation.
+
+//@ add-core-stubs
+//@ compile-flags: -Zsanitizer=kernel-address -Copt-level=0
+//@ revisions: aarch64 riscv64imac riscv64gc x86_64
+//@[aarch64] compile-flags: --target aarch64-unknown-none
+//@[aarch64] needs-llvm-components: aarch64
+//@[riscv64imac] compile-flags: --target riscv64imac-unknown-none-elf
+//@[riscv64imac] needs-llvm-components: riscv
+//@[riscv64gc] compile-flags: --target riscv64gc-unknown-none-elf
+//@[riscv64gc] needs-llvm-components: riscv
+//@[x86_64] compile-flags: --target x86_64-unknown-none
+//@[x86_64] needs-llvm-components: x86
+
+#![crate_type = "rlib"]
+#![feature(no_core, no_sanitize, lang_items)]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+// CHECK-LABEL: ; kasan_emits_instrumentation::unsanitized
+// CHECK-NEXT:  ; Function Attrs:
+// CHECK-NOT:   sanitize_address
+// CHECK:       start:
+// CHECK-NOT:   call void @__asan_report_load
+// CHECK:       }
+#[no_sanitize(address)]
+pub fn unsanitized(b: &mut u8) -> u8 {
+    *b
+}
+
+// CHECK-LABEL: ; kasan_emits_instrumentation::sanitized
+// CHECK-NEXT:  ; Function Attrs:
+// CHECK:       sanitize_address
+// CHECK:       start:
+// CHECK:       call void @__asan_report_load
+// CHECK:       }
+pub fn sanitized(b: &mut u8) -> u8 {
+    *b
+}
diff --git a/tests/codegen-llvm/sanitizer/kcfi/add-cfi-normalize-integers-flag.rs b/tests/codegen-llvm/sanitizer/kcfi/add-cfi-normalize-integers-flag.rs
new file mode 100644
index 00000000000..0be1ff19774
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/kcfi/add-cfi-normalize-integers-flag.rs
@@ -0,0 +1,20 @@
+// Verifies that "cfi-normalize-integers" module flag is added.
+//
+//@ add-core-stubs
+//@ revisions: aarch64 x86_64
+//@ [aarch64] compile-flags: --target aarch64-unknown-none
+//@ [aarch64] needs-llvm-components: aarch64
+//@ [x86_64] compile-flags: --target x86_64-unknown-none
+//@ [x86_64] needs-llvm-components: x86
+//@ compile-flags: -Ctarget-feature=-crt-static -Zsanitizer=kcfi -Zsanitizer-cfi-normalize-integers
+
+#![feature(no_core, lang_items)]
+#![crate_type = "lib"]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+pub fn foo() {}
+
+// CHECK: !{{[0-9]+}} = !{i32 4, !"cfi-normalize-integers", i32 1}
diff --git a/tests/codegen-llvm/sanitizer/kcfi/add-kcfi-arity-flag.rs b/tests/codegen-llvm/sanitizer/kcfi/add-kcfi-arity-flag.rs
new file mode 100644
index 00000000000..9a2290901d6
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/kcfi/add-kcfi-arity-flag.rs
@@ -0,0 +1,19 @@
+// Verifies that "kcfi-arity" module flag is added.
+//
+//@ add-core-stubs
+//@ revisions: x86_64
+//@ [x86_64] compile-flags: --target x86_64-unknown-none
+//@ [x86_64] needs-llvm-components: x86
+//@ compile-flags: -Ctarget-feature=-crt-static -Cpanic=abort -Zsanitizer=kcfi -Zsanitizer-kcfi-arity
+//@ min-llvm-version: 21.0.0
+
+#![feature(no_core, lang_items)]
+#![crate_type = "lib"]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+pub fn foo() {}
+
+// CHECK: !{{[0-9]+}} = !{i32 4, !"kcfi-arity", i32 1}
diff --git a/tests/codegen-llvm/sanitizer/kcfi/add-kcfi-flag.rs b/tests/codegen-llvm/sanitizer/kcfi/add-kcfi-flag.rs
new file mode 100644
index 00000000000..eabe0409c9a
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/kcfi/add-kcfi-flag.rs
@@ -0,0 +1,20 @@
+// Verifies that "kcfi" module flag is added.
+//
+//@ add-core-stubs
+//@ revisions: aarch64 x86_64
+//@ [aarch64] compile-flags: --target aarch64-unknown-none
+//@ [aarch64] needs-llvm-components: aarch64
+//@ [x86_64] compile-flags: --target x86_64-unknown-none
+//@ [x86_64] needs-llvm-components: x86
+//@ compile-flags: -Ctarget-feature=-crt-static -Zsanitizer=kcfi
+
+#![feature(no_core, lang_items)]
+#![crate_type = "lib"]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+pub fn foo() {}
+
+// CHECK: !{{[0-9]+}} = !{i32 4, !"kcfi", i32 1}
diff --git a/tests/codegen-llvm/sanitizer/kcfi/add-kcfi-offset-flag.rs b/tests/codegen-llvm/sanitizer/kcfi/add-kcfi-offset-flag.rs
new file mode 100644
index 00000000000..2f18c9d84b9
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/kcfi/add-kcfi-offset-flag.rs
@@ -0,0 +1,20 @@
+// Verifies that "kcfi-offset" module flag is added.
+//
+//@ add-core-stubs
+//@ revisions: aarch64 x86_64
+//@ [aarch64] compile-flags: --target aarch64-unknown-none
+//@ [aarch64] needs-llvm-components: aarch64
+//@ [x86_64] compile-flags: --target x86_64-unknown-none
+//@ [x86_64] needs-llvm-components: x86
+//@ compile-flags: -Ctarget-feature=-crt-static -Zsanitizer=kcfi -Z patchable-function-entry=4,3
+
+#![feature(no_core, lang_items, patchable_function_entry)]
+#![crate_type = "lib"]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+pub fn foo() {}
+
+// CHECK: !{{[0-9]+}} = !{i32 4, !"kcfi-offset", i32 3}
diff --git a/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-attr-no-sanitize.rs b/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-attr-no-sanitize.rs
new file mode 100644
index 00000000000..6b40918dd3a
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-attr-no-sanitize.rs
@@ -0,0 +1,27 @@
+// Verifies that KCFI operand bundles are omitted.
+//
+//@ add-core-stubs
+//@ revisions: aarch64 x86_64
+//@ [aarch64] compile-flags: --target aarch64-unknown-none
+//@ [aarch64] needs-llvm-components: aarch64
+//@ [x86_64] compile-flags: --target x86_64-unknown-none
+//@ [x86_64] needs-llvm-components:
+//@ compile-flags: -Cno-prepopulate-passes -Zsanitizer=kcfi -Copt-level=0
+
+#![crate_type = "lib"]
+#![feature(no_core, no_sanitize, lang_items)]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+#[no_sanitize(kcfi)]
+pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 {
+    // CHECK-LABEL: emit_kcfi_operand_bundle_attr_no_sanitize::foo
+    // CHECK:       Function Attrs: {{.*}}
+    // CHECK-LABEL: define{{.*}}foo{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}}
+    // CHECK:       start:
+    // CHECK-NOT:   {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg){{.*}}[ "kcfi"(i32 {{[-0-9]+}}) ]
+    // CHECK:       ret i32 {{%.+}}
+    f(arg)
+}
diff --git a/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-generalized.rs b/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-generalized.rs
new file mode 100644
index 00000000000..942b50deb02
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-generalized.rs
@@ -0,0 +1,41 @@
+// Verifies that generalized KCFI type metadata for functions are emitted.
+//
+//@ add-core-stubs
+//@ revisions: aarch64 x86_64
+//@ [aarch64] compile-flags: --target aarch64-unknown-none
+//@ [aarch64] needs-llvm-components: aarch64
+//@ [x86_64] compile-flags: --target x86_64-unknown-none
+//@ [x86_64] needs-llvm-components:
+//@ compile-flags: -Cno-prepopulate-passes -Zsanitizer=kcfi -Zsanitizer-cfi-generalize-pointers
+
+#![crate_type = "lib"]
+#![feature(no_core, lang_items)]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}foo
+    // CHECK-SAME:  {{.*}}!{{<unknown kind #36>|kcfi_type}} ![[TYPE1:[0-9]+]]
+    // CHECK:       {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg){{.*}}[ "kcfi"(i32 233085384) ]
+    f(arg)
+}
+
+pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}bar
+    // CHECK-SAME:  {{.*}}!{{<unknown kind #36>|kcfi_type}} ![[TYPE2:[0-9]+]]
+    // CHECK:       {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg1, i32 {{(noundef )*}}%arg2){{.*}}[ "kcfi"(i32 435418021) ]
+    f(arg1, arg2)
+}
+
+pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}baz
+    // CHECK-SAME:  {{.*}}!{{<unknown kind #36>|kcfi_type}} ![[TYPE3:[0-9]+]]
+    // CHECK:       {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg1, i32 {{(noundef )*}}%arg2, i32 {{(noundef )*}}%arg3){{.*}}[ "kcfi"(i32 -1003721339) ]
+    f(arg1, arg2, arg3)
+}
+
+// CHECK: ![[TYPE1]] = !{i32 -1741689296}
+// CHECK: ![[TYPE2]] = !{i32 489439372}
+// CHECK: ![[TYPE3]] = !{i32 2026563871}
diff --git a/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-normalized-generalized.rs b/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-normalized-generalized.rs
new file mode 100644
index 00000000000..c89d9bdd121
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-normalized-generalized.rs
@@ -0,0 +1,41 @@
+// Verifies that normalized and generalized KCFI type metadata for functions are emitted.
+//
+//@ add-core-stubs
+//@ revisions: aarch64 x86_64
+//@ [aarch64] compile-flags: --target aarch64-unknown-none
+//@ [aarch64] needs-llvm-components: aarch64
+//@ [x86_64] compile-flags: --target x86_64-unknown-none
+//@ [x86_64] needs-llvm-components:
+//@ compile-flags: -Cno-prepopulate-passes -Zsanitizer=kcfi -Zsanitizer-cfi-normalize-integers -Zsanitizer-cfi-generalize-pointers
+
+#![crate_type = "lib"]
+#![feature(no_core, lang_items)]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}foo
+    // CHECK-SAME:  {{.*}}!{{<unknown kind #36>|kcfi_type}} ![[TYPE1:[0-9]+]]
+    // CHECK:       {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg){{.*}}[ "kcfi"(i32 -686570305) ]
+    f(arg)
+}
+
+pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}bar
+    // CHECK-SAME:  {{.*}}!{{<unknown kind #36>|kcfi_type}} ![[TYPE2:[0-9]+]]
+    // CHECK:       {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg1, i32 {{(noundef )*}}%arg2){{.*}}[ "kcfi"(i32 1281038450) ]
+    f(arg1, arg2)
+}
+
+pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}baz
+    // CHECK-SAME:  {{.*}}!{{<unknown kind #36>|kcfi_type}} ![[TYPE3:[0-9]+]]
+    // CHECK:       {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg1, i32 {{(noundef )*}}%arg2, i32 {{(noundef )*}}%arg3){{.*}}[ "kcfi"(i32 -1751512973) ]
+    f(arg1, arg2, arg3)
+}
+
+// CHECK: ![[TYPE1]] = !{i32 975484707}
+// CHECK: ![[TYPE2]] = !{i32 1658833102}
+// CHECK: ![[TYPE3]] = !{i32 230429758}
diff --git a/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-normalized.rs b/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-normalized.rs
new file mode 100644
index 00000000000..220cae1a4fa
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-normalized.rs
@@ -0,0 +1,41 @@
+// Verifies that normalized KCFI type metadata for functions are emitted.
+//
+//@ add-core-stubs
+//@ revisions: aarch64 x86_64
+//@ [aarch64] compile-flags: --target aarch64-unknown-none
+//@ [aarch64] needs-llvm-components: aarch64
+//@ [x86_64] compile-flags: --target x86_64-unknown-none
+//@ [x86_64] needs-llvm-components:
+//@ compile-flags: -Cno-prepopulate-passes -Zsanitizer=kcfi -Zsanitizer-cfi-normalize-integers
+
+#![crate_type = "lib"]
+#![feature(no_core, lang_items)]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}foo
+    // CHECK-SAME:  {{.*}}!{{<unknown kind #36>|kcfi_type}} ![[TYPE1:[0-9]+]]
+    // CHECK:       {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg){{.*}}[ "kcfi"(i32 -841055669) ]
+    f(arg)
+}
+
+pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}bar
+    // CHECK-SAME:  {{.*}}!{{<unknown kind #36>|kcfi_type}} ![[TYPE2:[0-9]+]]
+    // CHECK:       {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg1, i32 {{(noundef )*}}%arg2){{.*}}[ "kcfi"(i32 1390819368) ]
+    f(arg1, arg2)
+}
+
+pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}baz
+    // CHECK-SAME:  {{.*}}!{{<unknown kind #36>|kcfi_type}} ![[TYPE3:[0-9]+]]
+    // CHECK:       {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg1, i32 {{(noundef )*}}%arg2, i32 {{(noundef )*}}%arg3){{.*}}[ "kcfi"(i32 586925835) ]
+    f(arg1, arg2, arg3)
+}
+
+// CHECK: ![[TYPE1]] = !{i32 -458317079}
+// CHECK: ![[TYPE2]] = !{i32 1737138182}
+// CHECK: ![[TYPE3]] = !{i32 197182412}
diff --git a/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi.rs b/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi.rs
new file mode 100644
index 00000000000..bb9a0005903
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi.rs
@@ -0,0 +1,41 @@
+// Verifies that KCFI type metadata for functions are emitted.
+//
+//@ add-core-stubs
+//@ revisions: aarch64 x86_64
+//@ [aarch64] compile-flags: --target aarch64-unknown-none
+//@ [aarch64] needs-llvm-components: aarch64
+//@ [x86_64] compile-flags: --target x86_64-unknown-none
+//@ [x86_64] needs-llvm-components:
+//@ compile-flags: -Cno-prepopulate-passes -Zsanitizer=kcfi -Copt-level=0
+
+#![crate_type = "lib"]
+#![feature(no_core, lang_items)]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}foo
+    // CHECK-SAME:  {{.*}}!{{<unknown kind #36>|kcfi_type}} ![[TYPE1:[0-9]+]]
+    // CHECK:       {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg){{.*}}[ "kcfi"(i32 -1666898348) ]
+    f(arg)
+}
+
+pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}bar
+    // CHECK-SAME:  {{.*}}!{{<unknown kind #36>|kcfi_type}} ![[TYPE2:[0-9]+]]
+    // CHECK:       {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg1, i32 {{(noundef )*}}%arg2){{.*}}[ "kcfi"(i32 -1789026986) ]
+    f(arg1, arg2)
+}
+
+pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}baz
+    // CHECK-SAME:  {{.*}}!{{<unknown kind #36>|kcfi_type}} ![[TYPE3:[0-9]+]]
+    // CHECK:       {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg1, i32 {{(noundef )*}}%arg2, i32 {{(noundef )*}}%arg3){{.*}}[ "kcfi"(i32 1248878270) ]
+    f(arg1, arg2, arg3)
+}
+
+// CHECK: ![[TYPE1]] = !{i32 653723426}
+// CHECK: ![[TYPE2]] = !{i32 412174924}
+// CHECK: ![[TYPE3]] = !{i32 -636668840}
diff --git a/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle.rs b/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle.rs
new file mode 100644
index 00000000000..8b844b99142
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle.rs
@@ -0,0 +1,24 @@
+// Verifies that KCFI operand bundles are emitted.
+//
+//@ add-core-stubs
+//@ revisions: aarch64 x86_64
+//@ [aarch64] compile-flags: --target aarch64-unknown-none
+//@ [aarch64] needs-llvm-components: aarch64
+//@ [x86_64] compile-flags: --target x86_64-unknown-none
+//@ [x86_64] needs-llvm-components:
+//@ compile-flags: -Cno-prepopulate-passes -Zsanitizer=kcfi -Copt-level=0
+
+#![crate_type = "lib"]
+#![feature(no_core, lang_items)]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}foo{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}}
+    // CHECK:       start:
+    // CHECK-NEXT:  {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg){{.*}}[ "kcfi"(i32 {{[-0-9]+}}) ]
+    // CHECK-NEXT:  ret i32 {{%.+}}
+    f(arg)
+}
diff --git a/tests/codegen-llvm/sanitizer/kcfi/emit-type-metadata-trait-objects.rs b/tests/codegen-llvm/sanitizer/kcfi/emit-type-metadata-trait-objects.rs
new file mode 100644
index 00000000000..15c107bea15
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/kcfi/emit-type-metadata-trait-objects.rs
@@ -0,0 +1,155 @@
+// Verifies that type metadata identifiers for trait objects are emitted correctly.
+//
+//@ add-core-stubs
+//@ revisions: aarch64 x86_64
+//@ [aarch64] compile-flags: --target aarch64-unknown-none
+//@ [aarch64] needs-llvm-components: aarch64
+//@ [x86_64] compile-flags: --target x86_64-unknown-none
+//@ [x86_64] needs-llvm-components:
+//@ compile-flags: -Cno-prepopulate-passes -Zsanitizer=kcfi -Copt-level=0
+
+#![crate_type = "lib"]
+#![feature(arbitrary_self_types, no_core, lang_items)]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+pub trait Trait1 {
+    fn foo(&self);
+}
+
+pub struct Type1;
+
+impl Trait1 for Type1 {
+    fn foo(&self) {}
+}
+
+pub trait Trait2<T> {
+    fn bar(&self);
+}
+
+pub struct Type2;
+
+impl Trait2<i32> for Type2 {
+    fn bar(&self) {}
+}
+
+pub trait Trait3<T> {
+    fn baz(&self, _: &T);
+}
+
+pub struct Type3;
+
+impl<T, U> Trait3<U> for T {
+    fn baz(&self, _: &U) {}
+}
+
+pub trait Trait4<'a, T> {
+    type Output: 'a;
+    fn qux(&self, _: &T) -> Self::Output;
+}
+
+pub struct Type4;
+
+impl<'a, T, U> Trait4<'a, U> for T {
+    type Output = &'a i32;
+    fn qux(&self, _: &U) -> Self::Output {
+        &0
+    }
+}
+
+pub trait Trait5<T, const N: usize> {
+    fn quux(&self, _: &[T; N]);
+}
+
+pub struct Type5;
+
+impl Copy for Type5 {}
+
+impl<T, U, const N: usize> Trait5<U, N> for T {
+    fn quux(&self, _: &[U; N]) {}
+}
+
+pub fn foo1(a: &dyn Trait1) {
+    a.foo();
+    // CHECK-LABEL: define{{.*}}4foo1{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}}
+    // CHECK:       call void %{{[0-9]}}(ptr align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE1:[[:print:]]+]]) ]
+}
+
+pub fn bar1() {
+    let a = Type1;
+    let b = &a as &dyn Trait1;
+    b.foo();
+    // CHECK-LABEL: define{{.*}}4bar1{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}}
+    // CHECK:       call void %{{[0-9]}}(ptr align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE1:[[:print:]]+]]) ]
+}
+
+pub fn foo2<T>(a: &dyn Trait2<T>) {
+    a.bar();
+    // CHECK-LABEL: define{{.*}}4foo2{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}}
+    // CHECK:       call void %{{[0-9]}}(ptr align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE2:[[:print:]]+]]) ]
+}
+
+pub fn bar2() {
+    let a = Type2;
+    foo2(&a);
+    let b = &a as &dyn Trait2<i32>;
+    b.bar();
+    // CHECK-LABEL: define{{.*}}4bar2{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}}
+    // CHECK:       call void %{{[0-9]}}(ptr align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE2:[[:print:]]+]]) ]
+}
+
+pub fn foo3(a: &dyn Trait3<Type3>) {
+    let b = Type3;
+    a.baz(&b);
+    // CHECK-LABEL: define{{.*}}4foo3{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}}
+    // CHECK:       call void %{{[0-9]}}(ptr align 1 {{%[a-z]\.0|%_[0-9]}}, ptr align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE3:[[:print:]]+]]) ]
+}
+
+pub fn bar3() {
+    let a = Type3;
+    foo3(&a);
+    let b = &a as &dyn Trait3<Type3>;
+    b.baz(&a);
+    // CHECK-LABEL: define{{.*}}4bar3{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}}
+    // CHECK:       call void %{{[0-9]}}(ptr align 1 {{%[a-z]\.0|%_[0-9]}}, ptr align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE3:[[:print:]]+]]) ]
+}
+
+pub fn foo4<'a>(a: &dyn Trait4<'a, Type4, Output = &'a i32>) {
+    let b = Type4;
+    a.qux(&b);
+    // CHECK-LABEL: define{{.*}}4foo4{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}}
+    // CHECK:       call align 4 ptr %{{[0-9]}}(ptr align 1 {{%[a-z]\.0|%_[0-9]}}, ptr align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE4:[[:print:]]+]]) ]
+}
+
+pub fn bar4<'a>() {
+    let a = Type4;
+    foo4(&a);
+    let b = &a as &dyn Trait4<'a, Type4, Output = &'a i32>;
+    b.qux(&a);
+    // CHECK-LABEL: define{{.*}}4bar4{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}}
+    // CHECK:       call align 4 ptr %{{[0-9]}}(ptr align 1 {{%[a-z]\.0|%_[0-9]}}, ptr align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE4:[[:print:]]+]]) ]
+}
+
+pub fn foo5(a: &dyn Trait5<Type5, 32>) {
+    let b = &[Type5; 32];
+    a.quux(&b);
+    // CHECK-LABEL: define{{.*}}4foo5{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}}
+    // CHECK:       call void %{{[0-9]}}(ptr align 1 {{%[a-z](\.0)*|%_[0-9]+]}}, ptr align 1 {{%[a-z](\.0)*|%_[0-9]+}}){{.*}}[ "kcfi"(i32 [[TYPE5:[[:print:]]+]]) ]
+}
+
+pub fn bar5() {
+    let a = &[Type5; 32];
+    foo5(&a);
+    let b = &a as &dyn Trait5<Type5, 32>;
+    b.quux(&a);
+    // CHECK-LABEL: define{{.*}}4bar5{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}}
+    // CHECK:       call void %{{[0-9]}}(ptr align 1 {{%[a-z](\.0)*|%_[0-9]+]}}, ptr align 1 {{%[a-z](\.0)*|%_[0-9]+}}){{.*}}[ "kcfi"(i32 [[TYPE5:[[:print:]]+]]) ]
+}
+
+// CHECK: !{{[0-9]+}} = !{i32 [[TYPE1]]}
+// CHECK: !{{[0-9]+}} = !{i32 [[TYPE2]]}
+// CHECK: !{{[0-9]+}} = !{i32 [[TYPE3]]}
+// CHECK: !{{[0-9]+}} = !{i32 [[TYPE4]]}
+// CHECK: !{{[0-9]+}} = !{i32 [[TYPE5]]}
diff --git a/tests/codegen-llvm/sanitizer/kcfi/naked-function.rs b/tests/codegen-llvm/sanitizer/kcfi/naked-function.rs
new file mode 100644
index 00000000000..2c8cdc919b8
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/kcfi/naked-function.rs
@@ -0,0 +1,47 @@
+//@ add-core-stubs
+//@ revisions: aarch64 x86_64
+//@ [aarch64] compile-flags: --target aarch64-unknown-none
+//@ [aarch64] needs-llvm-components: aarch64
+//@ [x86_64] compile-flags: --target x86_64-unknown-none
+//@ [x86_64] needs-llvm-components: x86
+//@ compile-flags: -Ctarget-feature=-crt-static -Zsanitizer=kcfi -Cno-prepopulate-passes -Copt-level=0
+
+#![feature(no_core, lang_items)]
+#![crate_type = "lib"]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+struct Thing;
+trait MyTrait {
+    #[unsafe(naked)]
+    extern "C" fn my_naked_function() {
+        // the real function is defined
+        // CHECK: .globl
+        // CHECK-SAME: my_naked_function
+        naked_asm!("ret")
+    }
+}
+impl MyTrait for Thing {}
+
+// the shim calls the real function
+// CHECK-LABEL: define
+// CHECK-SAME: my_naked_function
+// CHECK-SAME: reify.shim.fnptr
+
+// CHECK-LABEL: main
+#[unsafe(no_mangle)]
+pub fn main() {
+    // Trick the compiler into generating an indirect call.
+    const F: extern "C" fn() = Thing::my_naked_function;
+
+    // main calls the shim function
+    // CHECK: call void
+    // CHECK-SAME: my_naked_function
+    // CHECK-SAME: reify.shim.fnptr
+    (F)();
+}
+
+// CHECK: declare !kcfi_type
+// CHECK-SAME: my_naked_function
diff --git a/tests/codegen-llvm/sanitizer/memory-track-origins.rs b/tests/codegen-llvm/sanitizer/memory-track-origins.rs
new file mode 100644
index 00000000000..318c277e10c
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/memory-track-origins.rs
@@ -0,0 +1,31 @@
+// Verifies that MemorySanitizer track-origins level can be controlled
+// with -Zsanitizer-memory-track-origins option.
+//
+//@ needs-sanitizer-memory
+//@ revisions:MSAN-0 MSAN-1 MSAN-2 MSAN-1-LTO MSAN-2-LTO
+//
+//@ compile-flags: -Zsanitizer=memory -Ctarget-feature=-crt-static
+//@[MSAN-0] compile-flags:
+//@[MSAN-1] compile-flags: -Zsanitizer-memory-track-origins=1
+//@[MSAN-2] compile-flags: -Zsanitizer-memory-track-origins
+//@[MSAN-1-LTO] compile-flags: -Zsanitizer-memory-track-origins=1 -C lto=fat
+//@[MSAN-2-LTO] compile-flags: -Zsanitizer-memory-track-origins -C lto=fat
+
+#![crate_type = "lib"]
+
+// MSAN-0-NOT: @__msan_track_origins
+// MSAN-1:     @__msan_track_origins = weak_odr {{.*}}constant i32 1
+// MSAN-2:     @__msan_track_origins = weak_odr {{.*}}constant i32 2
+// MSAN-1-LTO: @__msan_track_origins = weak_odr {{.*}}constant i32 1
+// MSAN-2-LTO: @__msan_track_origins = weak_odr {{.*}}constant i32 2
+//
+// MSAN-0-LABEL: define void @copy(
+// MSAN-1-LABEL: define void @copy(
+// MSAN-2-LABEL: define void @copy(
+#[no_mangle]
+pub fn copy(dst: &mut i32, src: &i32) {
+    // MSAN-0-NOT: call i32 @__msan_chain_origin(
+    // MSAN-1-NOT: call i32 @__msan_chain_origin(
+    // MSAN-2:     call i32 @__msan_chain_origin(
+    *dst = *src;
+}
diff --git a/tests/codegen-llvm/sanitizer/memtag-attr-check.rs b/tests/codegen-llvm/sanitizer/memtag-attr-check.rs
new file mode 100644
index 00000000000..ffe3a2322a2
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/memtag-attr-check.rs
@@ -0,0 +1,12 @@
+// This tests that the sanitize_memtag attribute is
+// applied when enabling the memtag sanitizer.
+//
+//@ needs-sanitizer-memtag
+//@ compile-flags: -Zsanitizer=memtag -Ctarget-feature=+mte -Copt-level=0
+
+#![crate_type = "lib"]
+
+// CHECK: ; Function Attrs:{{.*}}sanitize_memtag
+pub fn tagged() {}
+
+// CHECK: attributes #0 = {{.*}}sanitize_memtag
diff --git a/tests/codegen-llvm/sanitizer/no-sanitize-inlining.rs b/tests/codegen-llvm/sanitizer/no-sanitize-inlining.rs
new file mode 100644
index 00000000000..4bd832d2ab1
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/no-sanitize-inlining.rs
@@ -0,0 +1,31 @@
+// Verifies that no_sanitize attribute prevents inlining when
+// given sanitizer is enabled, but has no effect on inlining otherwise.
+//
+//@ needs-sanitizer-address
+//@ needs-sanitizer-leak
+//@ revisions: ASAN LSAN
+//@       compile-flags: -Copt-level=3 -Zmir-opt-level=4 -Ctarget-feature=-crt-static
+//@[ASAN] compile-flags: -Zsanitizer=address
+//@[LSAN] compile-flags: -Zsanitizer=leak
+
+#![crate_type = "lib"]
+#![feature(no_sanitize)]
+
+// ASAN-LABEL: define void @test
+// ASAN:         call {{.*}} @random_inline
+// ASAN:       }
+//
+// LSAN-LABEL: define void @test
+// LSAN-NOT:     call
+// LSAN:       }
+#[no_mangle]
+pub fn test(n: &mut u32) {
+    random_inline(n);
+}
+
+#[no_sanitize(address)]
+#[inline]
+#[no_mangle]
+pub fn random_inline(n: &mut u32) {
+    *n = 42;
+}
diff --git a/tests/codegen-llvm/sanitizer/no-sanitize.rs b/tests/codegen-llvm/sanitizer/no-sanitize.rs
new file mode 100644
index 00000000000..2a309f6b9c6
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/no-sanitize.rs
@@ -0,0 +1,39 @@
+// Verifies that no_sanitize attribute can be used to
+// selectively disable sanitizer instrumentation.
+//
+//@ needs-sanitizer-address
+//@ compile-flags: -Zsanitizer=address -Ctarget-feature=-crt-static -Copt-level=0
+
+#![crate_type = "lib"]
+#![feature(no_sanitize)]
+
+// CHECK:     @UNSANITIZED = constant{{.*}} no_sanitize_address
+// CHECK-NOT: @__asan_global_UNSANITIZED
+#[no_mangle]
+#[no_sanitize(address)]
+pub static UNSANITIZED: u32 = 0;
+
+// CHECK: @__asan_global_SANITIZED
+#[no_mangle]
+pub static SANITIZED: u32 = 0;
+
+// CHECK-LABEL: ; no_sanitize::unsanitized
+// CHECK-NEXT:  ; Function Attrs:
+// CHECK-NOT:   sanitize_address
+// CHECK:       start:
+// CHECK-NOT:   call void @__asan_report_load
+// CHECK:       }
+#[no_sanitize(address)]
+pub fn unsanitized(b: &mut u8) -> u8 {
+    *b
+}
+
+// CHECK-LABEL: ; no_sanitize::sanitized
+// CHECK-NEXT:  ; Function Attrs:
+// CHECK:       sanitize_address
+// CHECK:       start:
+// CHECK:       call void @__asan_report_load
+// CHECK:       }
+pub fn sanitized(b: &mut u8) -> u8 {
+    *b
+}
diff --git a/tests/codegen-llvm/sanitizer/riscv64-shadow-call-stack.rs b/tests/codegen-llvm/sanitizer/riscv64-shadow-call-stack.rs
new file mode 100644
index 00000000000..945e46218d0
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/riscv64-shadow-call-stack.rs
@@ -0,0 +1,18 @@
+//@ add-core-stubs
+//@ compile-flags: --target riscv64imac-unknown-none-elf -Zsanitizer=shadow-call-stack
+//@ needs-llvm-components: riscv
+
+#![allow(internal_features)]
+#![crate_type = "rlib"]
+#![feature(no_core, lang_items)]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+// CHECK: ; Function Attrs:{{.*}}shadowcallstack
+// CHECK: define dso_local void @foo() unnamed_addr #0
+#[no_mangle]
+pub fn foo() {}
+
+// CHECK: attributes #0 = {{.*}}shadowcallstack{{.*}}
diff --git a/tests/codegen-llvm/sanitizer/safestack-attr-check.rs b/tests/codegen-llvm/sanitizer/safestack-attr-check.rs
new file mode 100644
index 00000000000..050a60333af
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/safestack-attr-check.rs
@@ -0,0 +1,11 @@
+// This tests that the safestack attribute is applied when enabling the safe-stack sanitizer.
+//
+//@ needs-sanitizer-safestack
+//@ compile-flags: -Zsanitizer=safestack -Copt-level=0
+
+#![crate_type = "lib"]
+
+// CHECK: ; Function Attrs:{{.*}}safestack
+pub fn tagged() {}
+
+// CHECK: attributes #0 = {{.*}}safestack
diff --git a/tests/codegen-llvm/sanitizer/sanitizer-recover.rs b/tests/codegen-llvm/sanitizer/sanitizer-recover.rs
new file mode 100644
index 00000000000..6b659320481
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/sanitizer-recover.rs
@@ -0,0 +1,50 @@
+// Verifies that AddressSanitizer and MemorySanitizer
+// recovery mode can be enabled with -Zsanitizer-recover.
+//
+//@ needs-sanitizer-address
+//@ needs-sanitizer-memory
+//@ revisions:ASAN ASAN-RECOVER MSAN MSAN-RECOVER MSAN-RECOVER-LTO
+//@ no-prefer-dynamic
+//
+//@                   compile-flags: -Ctarget-feature=-crt-static
+//@[ASAN]             compile-flags: -Zsanitizer=address -Copt-level=0
+//@[ASAN-RECOVER]     compile-flags: -Zsanitizer=address -Zsanitizer-recover=address -Copt-level=0
+//@[MSAN]             compile-flags: -Zsanitizer=memory
+//@[MSAN-RECOVER]     compile-flags: -Zsanitizer=memory  -Zsanitizer-recover=memory
+//@[MSAN-RECOVER-LTO] compile-flags: -Zsanitizer=memory  -Zsanitizer-recover=memory -C lto=fat
+//
+// MSAN-NOT:         @__msan_keep_going
+// MSAN-RECOVER:     @__msan_keep_going = weak_odr {{.*}}constant i32 1
+// MSAN-RECOVER-LTO: @__msan_keep_going = weak_odr {{.*}}constant i32 1
+
+// ASAN-LABEL: define dso_local i32 @penguin(
+// ASAN:         call void @__asan_report_load4(i64 %0)
+// ASAN:         unreachable
+// ASAN:       }
+//
+// ASAN-RECOVER-LABEL: define dso_local i32 @penguin(
+// ASAN-RECOVER:         call void @__asan_report_load4_noabort(
+// ASAN-RECOVER-NOT:     unreachable
+// ASAN:               }
+//
+// MSAN-LABEL: define dso_local noundef i32 @penguin(
+// MSAN:         call void @__msan_warning{{(_with_origin_noreturn\(i32 0\)|_noreturn\(\))}}
+// MSAN:         unreachable
+// MSAN:       }
+//
+// MSAN-RECOVER-LABEL: define dso_local noundef i32 @penguin(
+// MSAN-RECOVER:         call void @__msan_warning{{(_with_origin\(i32 0\)|\(\))}}
+// MSAN-RECOVER-NOT:     unreachable
+// MSAN-RECOVER:       }
+//
+// MSAN-RECOVER-LTO-LABEL: define dso_local noundef i32 @penguin(
+// MSAN-RECOVER-LTO:          call void @__msan_warning{{(_with_origin\(i32 0\)|\(\))}}
+// MSAN-RECOVER-LTO-NOT:      unreachable
+// MSAN-RECOVER-LTO:       }
+//
+#[no_mangle]
+pub fn penguin(p: &mut i32) -> i32 {
+    *p
+}
+
+fn main() {}
diff --git a/tests/codegen-llvm/sanitizer/scs-attr-check.rs b/tests/codegen-llvm/sanitizer/scs-attr-check.rs
new file mode 100644
index 00000000000..6f4cbc2c0a6
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/scs-attr-check.rs
@@ -0,0 +1,17 @@
+// This tests that the shadowcallstack attribute is
+// applied when enabling the shadow-call-stack sanitizer.
+//
+//@ needs-sanitizer-shadow-call-stack
+//@ compile-flags: -Zsanitizer=shadow-call-stack
+
+#![crate_type = "lib"]
+#![feature(no_sanitize)]
+
+// CHECK: ; sanitizer_scs_attr_check::scs
+// CHECK-NEXT: ; Function Attrs:{{.*}}shadowcallstack
+pub fn scs() {}
+
+// CHECK: ; sanitizer_scs_attr_check::no_scs
+// CHECK-NOT: ; Function Attrs:{{.*}}shadowcallstack
+#[no_sanitize(shadow_call_stack)]
+pub fn no_scs() {}
diff --git a/tests/codegen-llvm/scalar-pair-bool.rs b/tests/codegen-llvm/scalar-pair-bool.rs
new file mode 100644
index 00000000000..def3b32f71a
--- /dev/null
+++ b/tests/codegen-llvm/scalar-pair-bool.rs
@@ -0,0 +1,45 @@
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+
+// CHECK: define{{.*}}{ i1, i1 } @pair_bool_bool(i1 noundef zeroext %pair.0, i1 noundef zeroext %pair.1)
+#[no_mangle]
+pub fn pair_bool_bool(pair: (bool, bool)) -> (bool, bool) {
+    pair
+}
+
+// CHECK: define{{.*}}{ i1, i32 } @pair_bool_i32(i1 noundef zeroext %pair.0, i32 noundef %pair.1)
+#[no_mangle]
+pub fn pair_bool_i32(pair: (bool, i32)) -> (bool, i32) {
+    pair
+}
+
+// CHECK: define{{.*}}{ i32, i1 } @pair_i32_bool(i32 noundef %pair.0, i1 noundef zeroext %pair.1)
+#[no_mangle]
+pub fn pair_i32_bool(pair: (i32, bool)) -> (i32, bool) {
+    pair
+}
+
+// CHECK: define{{.*}}{ i1, i1 } @pair_and_or(i1 noundef zeroext %_1.0, i1 noundef zeroext %_1.1)
+#[no_mangle]
+pub fn pair_and_or((a, b): (bool, bool)) -> (bool, bool) {
+    // Make sure it can operate directly on the unpacked args
+    // (but it might not be using simple and/or instructions)
+    // CHECK-DAG: %_1.0
+    // CHECK-DAG: %_1.1
+    (a && b, a || b)
+}
+
+// CHECK: define{{.*}}void @pair_branches(i1 noundef zeroext %_1.0, i1 noundef zeroext %_1.1)
+#[no_mangle]
+pub fn pair_branches((a, b): (bool, bool)) {
+    // Make sure it can branch directly on the unpacked bool args
+    // CHECK: br i1 %_1.0
+    if a {
+        println!("Hello!");
+    }
+    // CHECK: br i1 %_1.1
+    if b {
+        println!("Goodbye!");
+    }
+}
diff --git a/tests/codegen-llvm/set-discriminant-invalid.rs b/tests/codegen-llvm/set-discriminant-invalid.rs
new file mode 100644
index 00000000000..dd584ef1c14
--- /dev/null
+++ b/tests/codegen-llvm/set-discriminant-invalid.rs
@@ -0,0 +1,34 @@
+//@ compile-flags: -C opt-level=0
+#![crate_type = "lib"]
+
+pub enum ApiError {}
+#[allow(dead_code)]
+pub struct TokioError {
+    b: bool,
+}
+pub enum Error {
+    Api { source: ApiError },
+    Ethereum,
+    Tokio { source: TokioError },
+}
+struct Api;
+impl IntoError<Error> for Api {
+    type Source = ApiError;
+    // CHECK-LABEL: @into_error
+    // CHECK: llvm.trap()
+    // Also check the next instruction to make sure we do not match against `trap`
+    // elsewhere in the code.
+    // CHECK-NEXT: ret i8 poison
+    #[no_mangle]
+    fn into_error(self, error: Self::Source) -> Error {
+        Error::Api { source: error }
+    }
+}
+
+pub trait IntoError<E> {
+    /// The underlying error
+    type Source;
+
+    /// Combine the information to produce the error
+    fn into_error(self, source: Self::Source) -> E;
+}
diff --git a/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-abs.rs b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-abs.rs
new file mode 100644
index 00000000000..baf445d0a1b
--- /dev/null
+++ b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-abs.rs
@@ -0,0 +1,60 @@
+//@ compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+#![feature(repr_simd, core_intrinsics)]
+#![allow(non_camel_case_types)]
+
+#[path = "../../auxiliary/minisimd.rs"]
+mod minisimd;
+use minisimd::*;
+
+use std::intrinsics::simd::simd_fabs;
+
+// CHECK-LABEL: @fabs_32x2
+#[no_mangle]
+pub unsafe fn fabs_32x2(a: f32x2) -> f32x2 {
+    // CHECK: call <2 x float> @llvm.fabs.v2f32
+    simd_fabs(a)
+}
+
+// CHECK-LABEL: @fabs_32x4
+#[no_mangle]
+pub unsafe fn fabs_32x4(a: f32x4) -> f32x4 {
+    // CHECK: call <4 x float> @llvm.fabs.v4f32
+    simd_fabs(a)
+}
+
+// CHECK-LABEL: @fabs_32x8
+#[no_mangle]
+pub unsafe fn fabs_32x8(a: f32x8) -> f32x8 {
+    // CHECK: call <8 x float> @llvm.fabs.v8f32
+    simd_fabs(a)
+}
+
+// CHECK-LABEL: @fabs_32x16
+#[no_mangle]
+pub unsafe fn fabs_32x16(a: f32x16) -> f32x16 {
+    // CHECK: call <16 x float> @llvm.fabs.v16f32
+    simd_fabs(a)
+}
+
+// CHECK-LABEL: @fabs_64x4
+#[no_mangle]
+pub unsafe fn fabs_64x4(a: f64x4) -> f64x4 {
+    // CHECK: call <4 x double> @llvm.fabs.v4f64
+    simd_fabs(a)
+}
+
+// CHECK-LABEL: @fabs_64x2
+#[no_mangle]
+pub unsafe fn fabs_64x2(a: f64x2) -> f64x2 {
+    // CHECK: call <2 x double> @llvm.fabs.v2f64
+    simd_fabs(a)
+}
+
+// CHECK-LABEL: @fabs_64x8
+#[no_mangle]
+pub unsafe fn fabs_64x8(a: f64x8) -> f64x8 {
+    // CHECK: call <8 x double> @llvm.fabs.v8f64
+    simd_fabs(a)
+}
diff --git a/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-ceil.rs b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-ceil.rs
new file mode 100644
index 00000000000..096de569274
--- /dev/null
+++ b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-ceil.rs
@@ -0,0 +1,60 @@
+//@ compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+#![feature(repr_simd, core_intrinsics)]
+#![allow(non_camel_case_types)]
+
+#[path = "../../auxiliary/minisimd.rs"]
+mod minisimd;
+use minisimd::*;
+
+use std::intrinsics::simd::simd_ceil;
+
+// CHECK-LABEL: @ceil_32x2
+#[no_mangle]
+pub unsafe fn ceil_32x2(a: f32x2) -> f32x2 {
+    // CHECK: call <2 x float> @llvm.ceil.v2f32
+    simd_ceil(a)
+}
+
+// CHECK-LABEL: @ceil_32x4
+#[no_mangle]
+pub unsafe fn ceil_32x4(a: f32x4) -> f32x4 {
+    // CHECK: call <4 x float> @llvm.ceil.v4f32
+    simd_ceil(a)
+}
+
+// CHECK-LABEL: @ceil_32x8
+#[no_mangle]
+pub unsafe fn ceil_32x8(a: f32x8) -> f32x8 {
+    // CHECK: call <8 x float> @llvm.ceil.v8f32
+    simd_ceil(a)
+}
+
+// CHECK-LABEL: @ceil_32x16
+#[no_mangle]
+pub unsafe fn ceil_32x16(a: f32x16) -> f32x16 {
+    // CHECK: call <16 x float> @llvm.ceil.v16f32
+    simd_ceil(a)
+}
+
+// CHECK-LABEL: @ceil_64x4
+#[no_mangle]
+pub unsafe fn ceil_64x4(a: f64x4) -> f64x4 {
+    // CHECK: call <4 x double> @llvm.ceil.v4f64
+    simd_ceil(a)
+}
+
+// CHECK-LABEL: @ceil_64x2
+#[no_mangle]
+pub unsafe fn ceil_64x2(a: f64x2) -> f64x2 {
+    // CHECK: call <2 x double> @llvm.ceil.v2f64
+    simd_ceil(a)
+}
+
+// CHECK-LABEL: @ceil_64x8
+#[no_mangle]
+pub unsafe fn ceil_64x8(a: f64x8) -> f64x8 {
+    // CHECK: call <8 x double> @llvm.ceil.v8f64
+    simd_ceil(a)
+}
diff --git a/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-cos.rs b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-cos.rs
new file mode 100644
index 00000000000..5b2197924bc
--- /dev/null
+++ b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-cos.rs
@@ -0,0 +1,60 @@
+//@ compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+#![feature(repr_simd, core_intrinsics)]
+#![allow(non_camel_case_types)]
+
+#[path = "../../auxiliary/minisimd.rs"]
+mod minisimd;
+use minisimd::*;
+
+use std::intrinsics::simd::simd_fcos;
+
+// CHECK-LABEL: @fcos_32x2
+#[no_mangle]
+pub unsafe fn fcos_32x2(a: f32x2) -> f32x2 {
+    // CHECK: call <2 x float> @llvm.cos.v2f32
+    simd_fcos(a)
+}
+
+// CHECK-LABEL: @fcos_32x4
+#[no_mangle]
+pub unsafe fn fcos_32x4(a: f32x4) -> f32x4 {
+    // CHECK: call <4 x float> @llvm.cos.v4f32
+    simd_fcos(a)
+}
+
+// CHECK-LABEL: @fcos_32x8
+#[no_mangle]
+pub unsafe fn fcos_32x8(a: f32x8) -> f32x8 {
+    // CHECK: call <8 x float> @llvm.cos.v8f32
+    simd_fcos(a)
+}
+
+// CHECK-LABEL: @fcos_32x16
+#[no_mangle]
+pub unsafe fn fcos_32x16(a: f32x16) -> f32x16 {
+    // CHECK: call <16 x float> @llvm.cos.v16f32
+    simd_fcos(a)
+}
+
+// CHECK-LABEL: @fcos_64x4
+#[no_mangle]
+pub unsafe fn fcos_64x4(a: f64x4) -> f64x4 {
+    // CHECK: call <4 x double> @llvm.cos.v4f64
+    simd_fcos(a)
+}
+
+// CHECK-LABEL: @fcos_64x2
+#[no_mangle]
+pub unsafe fn fcos_64x2(a: f64x2) -> f64x2 {
+    // CHECK: call <2 x double> @llvm.cos.v2f64
+    simd_fcos(a)
+}
+
+// CHECK-LABEL: @fcos_64x8
+#[no_mangle]
+pub unsafe fn fcos_64x8(a: f64x8) -> f64x8 {
+    // CHECK: call <8 x double> @llvm.cos.v8f64
+    simd_fcos(a)
+}
diff --git a/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-exp.rs b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-exp.rs
new file mode 100644
index 00000000000..d4eadb36c65
--- /dev/null
+++ b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-exp.rs
@@ -0,0 +1,60 @@
+//@ compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+#![feature(repr_simd, core_intrinsics)]
+#![allow(non_camel_case_types)]
+
+#[path = "../../auxiliary/minisimd.rs"]
+mod minisimd;
+use minisimd::*;
+
+use std::intrinsics::simd::simd_fexp;
+
+// CHECK-LABEL: @exp_32x2
+#[no_mangle]
+pub unsafe fn exp_32x2(a: f32x2) -> f32x2 {
+    // CHECK: call <2 x float> @llvm.exp.v2f32
+    simd_fexp(a)
+}
+
+// CHECK-LABEL: @exp_32x4
+#[no_mangle]
+pub unsafe fn exp_32x4(a: f32x4) -> f32x4 {
+    // CHECK: call <4 x float> @llvm.exp.v4f32
+    simd_fexp(a)
+}
+
+// CHECK-LABEL: @exp_32x8
+#[no_mangle]
+pub unsafe fn exp_32x8(a: f32x8) -> f32x8 {
+    // CHECK: call <8 x float> @llvm.exp.v8f32
+    simd_fexp(a)
+}
+
+// CHECK-LABEL: @exp_32x16
+#[no_mangle]
+pub unsafe fn exp_32x16(a: f32x16) -> f32x16 {
+    // CHECK: call <16 x float> @llvm.exp.v16f32
+    simd_fexp(a)
+}
+
+// CHECK-LABEL: @exp_64x4
+#[no_mangle]
+pub unsafe fn exp_64x4(a: f64x4) -> f64x4 {
+    // CHECK: call <4 x double> @llvm.exp.v4f64
+    simd_fexp(a)
+}
+
+// CHECK-LABEL: @exp_64x2
+#[no_mangle]
+pub unsafe fn exp_64x2(a: f64x2) -> f64x2 {
+    // CHECK: call <2 x double> @llvm.exp.v2f64
+    simd_fexp(a)
+}
+
+// CHECK-LABEL: @exp_64x8
+#[no_mangle]
+pub unsafe fn exp_64x8(a: f64x8) -> f64x8 {
+    // CHECK: call <8 x double> @llvm.exp.v8f64
+    simd_fexp(a)
+}
diff --git a/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-exp2.rs b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-exp2.rs
new file mode 100644
index 00000000000..d32015b7990
--- /dev/null
+++ b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-exp2.rs
@@ -0,0 +1,60 @@
+//@ compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+#![feature(repr_simd, core_intrinsics)]
+#![allow(non_camel_case_types)]
+
+#[path = "../../auxiliary/minisimd.rs"]
+mod minisimd;
+use minisimd::*;
+
+use std::intrinsics::simd::simd_fexp2;
+
+// CHECK-LABEL: @exp2_32x2
+#[no_mangle]
+pub unsafe fn exp2_32x2(a: f32x2) -> f32x2 {
+    // CHECK: call <2 x float> @llvm.exp2.v2f32
+    simd_fexp2(a)
+}
+
+// CHECK-LABEL: @exp2_32x4
+#[no_mangle]
+pub unsafe fn exp2_32x4(a: f32x4) -> f32x4 {
+    // CHECK: call <4 x float> @llvm.exp2.v4f32
+    simd_fexp2(a)
+}
+
+// CHECK-LABEL: @exp2_32x8
+#[no_mangle]
+pub unsafe fn exp2_32x8(a: f32x8) -> f32x8 {
+    // CHECK: call <8 x float> @llvm.exp2.v8f32
+    simd_fexp2(a)
+}
+
+// CHECK-LABEL: @exp2_32x16
+#[no_mangle]
+pub unsafe fn exp2_32x16(a: f32x16) -> f32x16 {
+    // CHECK: call <16 x float> @llvm.exp2.v16f32
+    simd_fexp2(a)
+}
+
+// CHECK-LABEL: @exp2_64x4
+#[no_mangle]
+pub unsafe fn exp2_64x4(a: f64x4) -> f64x4 {
+    // CHECK: call <4 x double> @llvm.exp2.v4f64
+    simd_fexp2(a)
+}
+
+// CHECK-LABEL: @exp2_64x2
+#[no_mangle]
+pub unsafe fn exp2_64x2(a: f64x2) -> f64x2 {
+    // CHECK: call <2 x double> @llvm.exp2.v2f64
+    simd_fexp2(a)
+}
+
+// CHECK-LABEL: @exp2_64x8
+#[no_mangle]
+pub unsafe fn exp2_64x8(a: f64x8) -> f64x8 {
+    // CHECK: call <8 x double> @llvm.exp2.v8f64
+    simd_fexp2(a)
+}
diff --git a/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-floor.rs b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-floor.rs
new file mode 100644
index 00000000000..1e1c8ce0c35
--- /dev/null
+++ b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-floor.rs
@@ -0,0 +1,60 @@
+//@ compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+#![feature(repr_simd, core_intrinsics)]
+#![allow(non_camel_case_types)]
+
+#[path = "../../auxiliary/minisimd.rs"]
+mod minisimd;
+use minisimd::*;
+
+use std::intrinsics::simd::simd_floor;
+
+// CHECK-LABEL: @floor_32x2
+#[no_mangle]
+pub unsafe fn floor_32x2(a: f32x2) -> f32x2 {
+    // CHECK: call <2 x float> @llvm.floor.v2f32
+    simd_floor(a)
+}
+
+// CHECK-LABEL: @floor_32x4
+#[no_mangle]
+pub unsafe fn floor_32x4(a: f32x4) -> f32x4 {
+    // CHECK: call <4 x float> @llvm.floor.v4f32
+    simd_floor(a)
+}
+
+// CHECK-LABEL: @floor_32x8
+#[no_mangle]
+pub unsafe fn floor_32x8(a: f32x8) -> f32x8 {
+    // CHECK: call <8 x float> @llvm.floor.v8f32
+    simd_floor(a)
+}
+
+// CHECK-LABEL: @floor_32x16
+#[no_mangle]
+pub unsafe fn floor_32x16(a: f32x16) -> f32x16 {
+    // CHECK: call <16 x float> @llvm.floor.v16f32
+    simd_floor(a)
+}
+
+// CHECK-LABEL: @floor_64x4
+#[no_mangle]
+pub unsafe fn floor_64x4(a: f64x4) -> f64x4 {
+    // CHECK: call <4 x double> @llvm.floor.v4f64
+    simd_floor(a)
+}
+
+// CHECK-LABEL: @floor_64x2
+#[no_mangle]
+pub unsafe fn floor_64x2(a: f64x2) -> f64x2 {
+    // CHECK: call <2 x double> @llvm.floor.v2f64
+    simd_floor(a)
+}
+
+// CHECK-LABEL: @floor_64x8
+#[no_mangle]
+pub unsafe fn floor_64x8(a: f64x8) -> f64x8 {
+    // CHECK: call <8 x double> @llvm.floor.v8f64
+    simd_floor(a)
+}
diff --git a/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-fma.rs b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-fma.rs
new file mode 100644
index 00000000000..982077d81f9
--- /dev/null
+++ b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-fma.rs
@@ -0,0 +1,60 @@
+//@ compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+#![feature(repr_simd, core_intrinsics)]
+#![allow(non_camel_case_types)]
+
+#[path = "../../auxiliary/minisimd.rs"]
+mod minisimd;
+use minisimd::*;
+
+use std::intrinsics::simd::simd_fma;
+
+// CHECK-LABEL: @fma_32x2
+#[no_mangle]
+pub unsafe fn fma_32x2(a: f32x2, b: f32x2, c: f32x2) -> f32x2 {
+    // CHECK: call <2 x float> @llvm.fma.v2f32
+    simd_fma(a, b, c)
+}
+
+// CHECK-LABEL: @fma_32x4
+#[no_mangle]
+pub unsafe fn fma_32x4(a: f32x4, b: f32x4, c: f32x4) -> f32x4 {
+    // CHECK: call <4 x float> @llvm.fma.v4f32
+    simd_fma(a, b, c)
+}
+
+// CHECK-LABEL: @fma_32x8
+#[no_mangle]
+pub unsafe fn fma_32x8(a: f32x8, b: f32x8, c: f32x8) -> f32x8 {
+    // CHECK: call <8 x float> @llvm.fma.v8f32
+    simd_fma(a, b, c)
+}
+
+// CHECK-LABEL: @fma_32x16
+#[no_mangle]
+pub unsafe fn fma_32x16(a: f32x16, b: f32x16, c: f32x16) -> f32x16 {
+    // CHECK: call <16 x float> @llvm.fma.v16f32
+    simd_fma(a, b, c)
+}
+
+// CHECK-LABEL: @fma_64x4
+#[no_mangle]
+pub unsafe fn fma_64x4(a: f64x4, b: f64x4, c: f64x4) -> f64x4 {
+    // CHECK: call <4 x double> @llvm.fma.v4f64
+    simd_fma(a, b, c)
+}
+
+// CHECK-LABEL: @fma_64x2
+#[no_mangle]
+pub unsafe fn fma_64x2(a: f64x2, b: f64x2, c: f64x2) -> f64x2 {
+    // CHECK: call <2 x double> @llvm.fma.v2f64
+    simd_fma(a, b, c)
+}
+
+// CHECK-LABEL: @fma_64x8
+#[no_mangle]
+pub unsafe fn fma_64x8(a: f64x8, b: f64x8, c: f64x8) -> f64x8 {
+    // CHECK: call <8 x double> @llvm.fma.v8f64
+    simd_fma(a, b, c)
+}
diff --git a/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-fsqrt.rs b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-fsqrt.rs
new file mode 100644
index 00000000000..e20a591f573
--- /dev/null
+++ b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-fsqrt.rs
@@ -0,0 +1,60 @@
+//@ compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+#![feature(repr_simd, core_intrinsics)]
+#![allow(non_camel_case_types)]
+
+#[path = "../../auxiliary/minisimd.rs"]
+mod minisimd;
+use minisimd::*;
+
+use std::intrinsics::simd::simd_fsqrt;
+
+// CHECK-LABEL: @fsqrt_32x2
+#[no_mangle]
+pub unsafe fn fsqrt_32x2(a: f32x2) -> f32x2 {
+    // CHECK: call <2 x float> @llvm.sqrt.v2f32
+    simd_fsqrt(a)
+}
+
+// CHECK-LABEL: @fsqrt_32x4
+#[no_mangle]
+pub unsafe fn fsqrt_32x4(a: f32x4) -> f32x4 {
+    // CHECK: call <4 x float> @llvm.sqrt.v4f32
+    simd_fsqrt(a)
+}
+
+// CHECK-LABEL: @fsqrt_32x8
+#[no_mangle]
+pub unsafe fn fsqrt_32x8(a: f32x8) -> f32x8 {
+    // CHECK: call <8 x float> @llvm.sqrt.v8f32
+    simd_fsqrt(a)
+}
+
+// CHECK-LABEL: @fsqrt_32x16
+#[no_mangle]
+pub unsafe fn fsqrt_32x16(a: f32x16) -> f32x16 {
+    // CHECK: call <16 x float> @llvm.sqrt.v16f32
+    simd_fsqrt(a)
+}
+
+// CHECK-LABEL: @fsqrt_64x4
+#[no_mangle]
+pub unsafe fn fsqrt_64x4(a: f64x4) -> f64x4 {
+    // CHECK: call <4 x double> @llvm.sqrt.v4f64
+    simd_fsqrt(a)
+}
+
+// CHECK-LABEL: @fsqrt_64x2
+#[no_mangle]
+pub unsafe fn fsqrt_64x2(a: f64x2) -> f64x2 {
+    // CHECK: call <2 x double> @llvm.sqrt.v2f64
+    simd_fsqrt(a)
+}
+
+// CHECK-LABEL: @fsqrt_64x8
+#[no_mangle]
+pub unsafe fn fsqrt_64x8(a: f64x8) -> f64x8 {
+    // CHECK: call <8 x double> @llvm.sqrt.v8f64
+    simd_fsqrt(a)
+}
diff --git a/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-log.rs b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-log.rs
new file mode 100644
index 00000000000..bf1ffc76330
--- /dev/null
+++ b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-log.rs
@@ -0,0 +1,60 @@
+//@ compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+#![feature(repr_simd, core_intrinsics)]
+#![allow(non_camel_case_types)]
+
+#[path = "../../auxiliary/minisimd.rs"]
+mod minisimd;
+use minisimd::*;
+
+use std::intrinsics::simd::simd_flog;
+
+// CHECK-LABEL: @log_32x2
+#[no_mangle]
+pub unsafe fn log_32x2(a: f32x2) -> f32x2 {
+    // CHECK: call <2 x float> @llvm.log.v2f32
+    simd_flog(a)
+}
+
+// CHECK-LABEL: @log_32x4
+#[no_mangle]
+pub unsafe fn log_32x4(a: f32x4) -> f32x4 {
+    // CHECK: call <4 x float> @llvm.log.v4f32
+    simd_flog(a)
+}
+
+// CHECK-LABEL: @log_32x8
+#[no_mangle]
+pub unsafe fn log_32x8(a: f32x8) -> f32x8 {
+    // CHECK: call <8 x float> @llvm.log.v8f32
+    simd_flog(a)
+}
+
+// CHECK-LABEL: @log_32x16
+#[no_mangle]
+pub unsafe fn log_32x16(a: f32x16) -> f32x16 {
+    // CHECK: call <16 x float> @llvm.log.v16f32
+    simd_flog(a)
+}
+
+// CHECK-LABEL: @log_64x4
+#[no_mangle]
+pub unsafe fn log_64x4(a: f64x4) -> f64x4 {
+    // CHECK: call <4 x double> @llvm.log.v4f64
+    simd_flog(a)
+}
+
+// CHECK-LABEL: @log_64x2
+#[no_mangle]
+pub unsafe fn log_64x2(a: f64x2) -> f64x2 {
+    // CHECK: call <2 x double> @llvm.log.v2f64
+    simd_flog(a)
+}
+
+// CHECK-LABEL: @log_64x8
+#[no_mangle]
+pub unsafe fn log_64x8(a: f64x8) -> f64x8 {
+    // CHECK: call <8 x double> @llvm.log.v8f64
+    simd_flog(a)
+}
diff --git a/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-log10.rs b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-log10.rs
new file mode 100644
index 00000000000..ccf484e0e41
--- /dev/null
+++ b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-log10.rs
@@ -0,0 +1,60 @@
+//@ compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+#![feature(repr_simd, core_intrinsics)]
+#![allow(non_camel_case_types)]
+
+#[path = "../../auxiliary/minisimd.rs"]
+mod minisimd;
+use minisimd::*;
+
+use std::intrinsics::simd::simd_flog10;
+
+// CHECK-LABEL: @log10_32x2
+#[no_mangle]
+pub unsafe fn log10_32x2(a: f32x2) -> f32x2 {
+    // CHECK: call <2 x float> @llvm.log10.v2f32
+    simd_flog10(a)
+}
+
+// CHECK-LABEL: @log10_32x4
+#[no_mangle]
+pub unsafe fn log10_32x4(a: f32x4) -> f32x4 {
+    // CHECK: call <4 x float> @llvm.log10.v4f32
+    simd_flog10(a)
+}
+
+// CHECK-LABEL: @log10_32x8
+#[no_mangle]
+pub unsafe fn log10_32x8(a: f32x8) -> f32x8 {
+    // CHECK: call <8 x float> @llvm.log10.v8f32
+    simd_flog10(a)
+}
+
+// CHECK-LABEL: @log10_32x16
+#[no_mangle]
+pub unsafe fn log10_32x16(a: f32x16) -> f32x16 {
+    // CHECK: call <16 x float> @llvm.log10.v16f32
+    simd_flog10(a)
+}
+
+// CHECK-LABEL: @log10_64x4
+#[no_mangle]
+pub unsafe fn log10_64x4(a: f64x4) -> f64x4 {
+    // CHECK: call <4 x double> @llvm.log10.v4f64
+    simd_flog10(a)
+}
+
+// CHECK-LABEL: @log10_64x2
+#[no_mangle]
+pub unsafe fn log10_64x2(a: f64x2) -> f64x2 {
+    // CHECK: call <2 x double> @llvm.log10.v2f64
+    simd_flog10(a)
+}
+
+// CHECK-LABEL: @log10_64x8
+#[no_mangle]
+pub unsafe fn log10_64x8(a: f64x8) -> f64x8 {
+    // CHECK: call <8 x double> @llvm.log10.v8f64
+    simd_flog10(a)
+}
diff --git a/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-log2.rs b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-log2.rs
new file mode 100644
index 00000000000..677d8b01e84
--- /dev/null
+++ b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-log2.rs
@@ -0,0 +1,60 @@
+//@ compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+#![feature(repr_simd, core_intrinsics)]
+#![allow(non_camel_case_types)]
+
+#[path = "../../auxiliary/minisimd.rs"]
+mod minisimd;
+use minisimd::*;
+
+use std::intrinsics::simd::simd_flog2;
+
+// CHECK-LABEL: @log2_32x2
+#[no_mangle]
+pub unsafe fn log2_32x2(a: f32x2) -> f32x2 {
+    // CHECK: call <2 x float> @llvm.log2.v2f32
+    simd_flog2(a)
+}
+
+// CHECK-LABEL: @log2_32x4
+#[no_mangle]
+pub unsafe fn log2_32x4(a: f32x4) -> f32x4 {
+    // CHECK: call <4 x float> @llvm.log2.v4f32
+    simd_flog2(a)
+}
+
+// CHECK-LABEL: @log2_32x8
+#[no_mangle]
+pub unsafe fn log2_32x8(a: f32x8) -> f32x8 {
+    // CHECK: call <8 x float> @llvm.log2.v8f32
+    simd_flog2(a)
+}
+
+// CHECK-LABEL: @log2_32x16
+#[no_mangle]
+pub unsafe fn log2_32x16(a: f32x16) -> f32x16 {
+    // CHECK: call <16 x float> @llvm.log2.v16f32
+    simd_flog2(a)
+}
+
+// CHECK-LABEL: @log2_64x4
+#[no_mangle]
+pub unsafe fn log2_64x4(a: f64x4) -> f64x4 {
+    // CHECK: call <4 x double> @llvm.log2.v4f64
+    simd_flog2(a)
+}
+
+// CHECK-LABEL: @log2_64x2
+#[no_mangle]
+pub unsafe fn log2_64x2(a: f64x2) -> f64x2 {
+    // CHECK: call <2 x double> @llvm.log2.v2f64
+    simd_flog2(a)
+}
+
+// CHECK-LABEL: @log2_64x8
+#[no_mangle]
+pub unsafe fn log2_64x8(a: f64x8) -> f64x8 {
+    // CHECK: call <8 x double> @llvm.log2.v8f64
+    simd_flog2(a)
+}
diff --git a/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-minmax.rs b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-minmax.rs
new file mode 100644
index 00000000000..8dd464a1bff
--- /dev/null
+++ b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-minmax.rs
@@ -0,0 +1,25 @@
+//@ compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+#![feature(repr_simd, core_intrinsics)]
+#![allow(non_camel_case_types)]
+
+#[path = "../../auxiliary/minisimd.rs"]
+mod minisimd;
+use minisimd::*;
+
+use std::intrinsics::simd::{simd_fmax, simd_fmin};
+
+// CHECK-LABEL: @fmin
+#[no_mangle]
+pub unsafe fn fmin(a: f32x4, b: f32x4) -> f32x4 {
+    // CHECK: call <4 x float> @llvm.minnum.v4f32
+    simd_fmin(a, b)
+}
+
+// CHECK-LABEL: @fmax
+#[no_mangle]
+pub unsafe fn fmax(a: f32x4, b: f32x4) -> f32x4 {
+    // CHECK: call <4 x float> @llvm.maxnum.v4f32
+    simd_fmax(a, b)
+}
diff --git a/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-sin.rs b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-sin.rs
new file mode 100644
index 00000000000..48becc72c0b
--- /dev/null
+++ b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-sin.rs
@@ -0,0 +1,60 @@
+//@ compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+#![feature(repr_simd, core_intrinsics)]
+#![allow(non_camel_case_types)]
+
+#[path = "../../auxiliary/minisimd.rs"]
+mod minisimd;
+use minisimd::*;
+
+use std::intrinsics::simd::simd_fsin;
+
+// CHECK-LABEL: @fsin_32x2
+#[no_mangle]
+pub unsafe fn fsin_32x2(a: f32x2) -> f32x2 {
+    // CHECK: call <2 x float> @llvm.sin.v2f32
+    simd_fsin(a)
+}
+
+// CHECK-LABEL: @fsin_32x4
+#[no_mangle]
+pub unsafe fn fsin_32x4(a: f32x4) -> f32x4 {
+    // CHECK: call <4 x float> @llvm.sin.v4f32
+    simd_fsin(a)
+}
+
+// CHECK-LABEL: @fsin_32x8
+#[no_mangle]
+pub unsafe fn fsin_32x8(a: f32x8) -> f32x8 {
+    // CHECK: call <8 x float> @llvm.sin.v8f32
+    simd_fsin(a)
+}
+
+// CHECK-LABEL: @fsin_32x16
+#[no_mangle]
+pub unsafe fn fsin_32x16(a: f32x16) -> f32x16 {
+    // CHECK: call <16 x float> @llvm.sin.v16f32
+    simd_fsin(a)
+}
+
+// CHECK-LABEL: @fsin_64x4
+#[no_mangle]
+pub unsafe fn fsin_64x4(a: f64x4) -> f64x4 {
+    // CHECK: call <4 x double> @llvm.sin.v4f64
+    simd_fsin(a)
+}
+
+// CHECK-LABEL: @fsin_64x2
+#[no_mangle]
+pub unsafe fn fsin_64x2(a: f64x2) -> f64x2 {
+    // CHECK: call <2 x double> @llvm.sin.v2f64
+    simd_fsin(a)
+}
+
+// CHECK-LABEL: @fsin_64x8
+#[no_mangle]
+pub unsafe fn fsin_64x8(a: f64x8) -> f64x8 {
+    // CHECK: call <8 x double> @llvm.sin.v8f64
+    simd_fsin(a)
+}
diff --git a/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.rs b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.rs
new file mode 100644
index 00000000000..06d46889715
--- /dev/null
+++ b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.rs
@@ -0,0 +1,579 @@
+//@ compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+#![feature(repr_simd, core_intrinsics)]
+#![allow(non_camel_case_types)]
+#![deny(unused)]
+
+#[path = "../../auxiliary/minisimd.rs"]
+mod minisimd;
+use minisimd::*;
+
+use std::intrinsics::simd::{simd_saturating_add, simd_saturating_sub};
+
+// NOTE(eddyb) `%{{x|0}}` is used because on some targets (e.g. WASM)
+// SIMD vectors are passed directly, resulting in `%x` being a vector,
+// while on others they're passed indirectly, resulting in `%x` being
+// a pointer to a vector, and `%0` a vector loaded from that pointer.
+// This is controlled by the target spec option `simd_types_indirect`.
+// The same applies to `%{{y|1}}` as well.
+
+// CHECK-LABEL: @sadd_i8x2
+#[no_mangle]
+pub unsafe fn sadd_i8x2(x: i8x2, y: i8x2) -> i8x2 {
+    // CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.sadd.sat.v2i8(<2 x i8> %{{x|0}}, <2 x i8> %{{y|1}})
+    simd_saturating_add(x, y)
+}
+
+// CHECK-LABEL: @sadd_i8x4
+#[no_mangle]
+pub unsafe fn sadd_i8x4(x: i8x4, y: i8x4) -> i8x4 {
+    // CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.sadd.sat.v4i8(<4 x i8> %{{x|0}}, <4 x i8> %{{y|1}})
+    simd_saturating_add(x, y)
+}
+
+// CHECK-LABEL: @sadd_i8x8
+#[no_mangle]
+pub unsafe fn sadd_i8x8(x: i8x8, y: i8x8) -> i8x8 {
+    // CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.sadd.sat.v8i8(<8 x i8> %{{x|0}}, <8 x i8> %{{y|1}})
+    simd_saturating_add(x, y)
+}
+
+// CHECK-LABEL: @sadd_i8x16
+#[no_mangle]
+pub unsafe fn sadd_i8x16(x: i8x16, y: i8x16) -> i8x16 {
+    // CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.sadd.sat.v16i8(<16 x i8> %{{x|0}}, <16 x i8> %{{y|1}})
+    simd_saturating_add(x, y)
+}
+
+// CHECK-LABEL: @sadd_i8x32
+#[no_mangle]
+pub unsafe fn sadd_i8x32(x: i8x32, y: i8x32) -> i8x32 {
+    // CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.sadd.sat.v32i8(<32 x i8> %{{x|0}}, <32 x i8> %{{y|1}})
+    simd_saturating_add(x, y)
+}
+
+// CHECK-LABEL: @sadd_i8x64
+#[no_mangle]
+pub unsafe fn sadd_i8x64(x: i8x64, y: i8x64) -> i8x64 {
+    // CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.sadd.sat.v64i8(<64 x i8> %{{x|0}}, <64 x i8> %{{y|1}})
+    simd_saturating_add(x, y)
+}
+
+// CHECK-LABEL: @sadd_i16x2
+#[no_mangle]
+pub unsafe fn sadd_i16x2(x: i16x2, y: i16x2) -> i16x2 {
+    // CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.sadd.sat.v2i16(<2 x i16> %{{x|0}}, <2 x i16> %{{y|1}})
+    simd_saturating_add(x, y)
+}
+
+// CHECK-LABEL: @sadd_i16x4
+#[no_mangle]
+pub unsafe fn sadd_i16x4(x: i16x4, y: i16x4) -> i16x4 {
+    // CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.sadd.sat.v4i16(<4 x i16> %{{x|0}}, <4 x i16> %{{y|1}})
+    simd_saturating_add(x, y)
+}
+
+// CHECK-LABEL: @sadd_i16x8
+#[no_mangle]
+pub unsafe fn sadd_i16x8(x: i16x8, y: i16x8) -> i16x8 {
+    // CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.sadd.sat.v8i16(<8 x i16> %{{x|0}}, <8 x i16> %{{y|1}})
+    simd_saturating_add(x, y)
+}
+
+// CHECK-LABEL: @sadd_i16x16
+#[no_mangle]
+pub unsafe fn sadd_i16x16(x: i16x16, y: i16x16) -> i16x16 {
+    // CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.sadd.sat.v16i16(<16 x i16> %{{x|0}}, <16 x i16> %{{y|1}})
+    simd_saturating_add(x, y)
+}
+
+// CHECK-LABEL: @sadd_i16x32
+#[no_mangle]
+pub unsafe fn sadd_i16x32(x: i16x32, y: i16x32) -> i16x32 {
+    // CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.sadd.sat.v32i16(<32 x i16> %{{x|0}}, <32 x i16> %{{y|1}})
+    simd_saturating_add(x, y)
+}
+
+// CHECK-LABEL: @sadd_i32x2
+#[no_mangle]
+pub unsafe fn sadd_i32x2(x: i32x2, y: i32x2) -> i32x2 {
+    // CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.sadd.sat.v2i32(<2 x i32> %{{x|0}}, <2 x i32> %{{y|1}})
+    simd_saturating_add(x, y)
+}
+
+// CHECK-LABEL: @sadd_i32x4
+#[no_mangle]
+pub unsafe fn sadd_i32x4(x: i32x4, y: i32x4) -> i32x4 {
+    // CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.sadd.sat.v4i32(<4 x i32> %{{x|0}}, <4 x i32> %{{y|1}})
+    simd_saturating_add(x, y)
+}
+
+// CHECK-LABEL: @sadd_i32x8
+#[no_mangle]
+pub unsafe fn sadd_i32x8(x: i32x8, y: i32x8) -> i32x8 {
+    // CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.sadd.sat.v8i32(<8 x i32> %{{x|0}}, <8 x i32> %{{y|1}})
+    simd_saturating_add(x, y)
+}
+
+// CHECK-LABEL: @sadd_i32x16
+#[no_mangle]
+pub unsafe fn sadd_i32x16(x: i32x16, y: i32x16) -> i32x16 {
+    // CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.sadd.sat.v16i32(<16 x i32> %{{x|0}}, <16 x i32> %{{y|1}})
+    simd_saturating_add(x, y)
+}
+
+// CHECK-LABEL: @sadd_i64x2
+#[no_mangle]
+pub unsafe fn sadd_i64x2(x: i64x2, y: i64x2) -> i64x2 {
+    // CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.sadd.sat.v2i64(<2 x i64> %{{x|0}}, <2 x i64> %{{y|1}})
+    simd_saturating_add(x, y)
+}
+
+// CHECK-LABEL: @sadd_i64x4
+#[no_mangle]
+pub unsafe fn sadd_i64x4(x: i64x4, y: i64x4) -> i64x4 {
+    // CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.sadd.sat.v4i64(<4 x i64> %{{x|0}}, <4 x i64> %{{y|1}})
+    simd_saturating_add(x, y)
+}
+
+// CHECK-LABEL: @sadd_i64x8
+#[no_mangle]
+pub unsafe fn sadd_i64x8(x: i64x8, y: i64x8) -> i64x8 {
+    // CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.sadd.sat.v8i64(<8 x i64> %{{x|0}}, <8 x i64> %{{y|1}})
+    simd_saturating_add(x, y)
+}
+
+// CHECK-LABEL: @sadd_i128x2
+#[no_mangle]
+pub unsafe fn sadd_i128x2(x: i128x2, y: i128x2) -> i128x2 {
+    // CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.sadd.sat.v2i128(<2 x i128> %{{x|0}}, <2 x i128> %{{y|1}})
+    simd_saturating_add(x, y)
+}
+
+// CHECK-LABEL: @sadd_i128x4
+#[no_mangle]
+pub unsafe fn sadd_i128x4(x: i128x4, y: i128x4) -> i128x4 {
+    // CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.sadd.sat.v4i128(<4 x i128> %{{x|0}}, <4 x i128> %{{y|1}})
+    simd_saturating_add(x, y)
+}
+
+// CHECK-LABEL: @uadd_u8x2
+#[no_mangle]
+pub unsafe fn uadd_u8x2(x: u8x2, y: u8x2) -> u8x2 {
+    // CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.uadd.sat.v2i8(<2 x i8> %{{x|0}}, <2 x i8> %{{y|1}})
+    simd_saturating_add(x, y)
+}
+
+// CHECK-LABEL: @uadd_u8x4
+#[no_mangle]
+pub unsafe fn uadd_u8x4(x: u8x4, y: u8x4) -> u8x4 {
+    // CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.uadd.sat.v4i8(<4 x i8> %{{x|0}}, <4 x i8> %{{y|1}})
+    simd_saturating_add(x, y)
+}
+
+// CHECK-LABEL: @uadd_u8x8
+#[no_mangle]
+pub unsafe fn uadd_u8x8(x: u8x8, y: u8x8) -> u8x8 {
+    // CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.uadd.sat.v8i8(<8 x i8> %{{x|0}}, <8 x i8> %{{y|1}})
+    simd_saturating_add(x, y)
+}
+
+// CHECK-LABEL: @uadd_u8x16
+#[no_mangle]
+pub unsafe fn uadd_u8x16(x: u8x16, y: u8x16) -> u8x16 {
+    // CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.uadd.sat.v16i8(<16 x i8> %{{x|0}}, <16 x i8> %{{y|1}})
+    simd_saturating_add(x, y)
+}
+
+// CHECK-LABEL: @uadd_u8x32
+#[no_mangle]
+pub unsafe fn uadd_u8x32(x: u8x32, y: u8x32) -> u8x32 {
+    // CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.uadd.sat.v32i8(<32 x i8> %{{x|0}}, <32 x i8> %{{y|1}})
+    simd_saturating_add(x, y)
+}
+
+// CHECK-LABEL: @uadd_u8x64
+#[no_mangle]
+pub unsafe fn uadd_u8x64(x: u8x64, y: u8x64) -> u8x64 {
+    // CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.uadd.sat.v64i8(<64 x i8> %{{x|0}}, <64 x i8> %{{y|1}})
+    simd_saturating_add(x, y)
+}
+
+// CHECK-LABEL: @uadd_u16x2
+#[no_mangle]
+pub unsafe fn uadd_u16x2(x: u16x2, y: u16x2) -> u16x2 {
+    // CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.uadd.sat.v2i16(<2 x i16> %{{x|0}}, <2 x i16> %{{y|1}})
+    simd_saturating_add(x, y)
+}
+
+// CHECK-LABEL: @uadd_u16x4
+#[no_mangle]
+pub unsafe fn uadd_u16x4(x: u16x4, y: u16x4) -> u16x4 {
+    // CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.uadd.sat.v4i16(<4 x i16> %{{x|0}}, <4 x i16> %{{y|1}})
+    simd_saturating_add(x, y)
+}
+
+// CHECK-LABEL: @uadd_u16x8
+#[no_mangle]
+pub unsafe fn uadd_u16x8(x: u16x8, y: u16x8) -> u16x8 {
+    // CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.uadd.sat.v8i16(<8 x i16> %{{x|0}}, <8 x i16> %{{y|1}})
+    simd_saturating_add(x, y)
+}
+
+// CHECK-LABEL: @uadd_u16x16
+#[no_mangle]
+pub unsafe fn uadd_u16x16(x: u16x16, y: u16x16) -> u16x16 {
+    // CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.uadd.sat.v16i16(<16 x i16> %{{x|0}}, <16 x i16> %{{y|1}})
+    simd_saturating_add(x, y)
+}
+
+// CHECK-LABEL: @uadd_u16x32
+#[no_mangle]
+pub unsafe fn uadd_u16x32(x: u16x32, y: u16x32) -> u16x32 {
+    // CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.uadd.sat.v32i16(<32 x i16> %{{x|0}}, <32 x i16> %{{y|1}})
+    simd_saturating_add(x, y)
+}
+
+// CHECK-LABEL: @uadd_u32x2
+#[no_mangle]
+pub unsafe fn uadd_u32x2(x: u32x2, y: u32x2) -> u32x2 {
+    // CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.uadd.sat.v2i32(<2 x i32> %{{x|0}}, <2 x i32> %{{y|1}})
+    simd_saturating_add(x, y)
+}
+
+// CHECK-LABEL: @uadd_u32x4
+#[no_mangle]
+pub unsafe fn uadd_u32x4(x: u32x4, y: u32x4) -> u32x4 {
+    // CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.uadd.sat.v4i32(<4 x i32> %{{x|0}}, <4 x i32> %{{y|1}})
+    simd_saturating_add(x, y)
+}
+
+// CHECK-LABEL: @uadd_u32x8
+#[no_mangle]
+pub unsafe fn uadd_u32x8(x: u32x8, y: u32x8) -> u32x8 {
+    // CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.uadd.sat.v8i32(<8 x i32> %{{x|0}}, <8 x i32> %{{y|1}})
+    simd_saturating_add(x, y)
+}
+
+// CHECK-LABEL: @uadd_u32x16
+#[no_mangle]
+pub unsafe fn uadd_u32x16(x: u32x16, y: u32x16) -> u32x16 {
+    // CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.uadd.sat.v16i32(<16 x i32> %{{x|0}}, <16 x i32> %{{y|1}})
+    simd_saturating_add(x, y)
+}
+
+// CHECK-LABEL: @uadd_u64x2
+#[no_mangle]
+pub unsafe fn uadd_u64x2(x: u64x2, y: u64x2) -> u64x2 {
+    // CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.uadd.sat.v2i64(<2 x i64> %{{x|0}}, <2 x i64> %{{y|1}})
+    simd_saturating_add(x, y)
+}
+
+// CHECK-LABEL: @uadd_u64x4
+#[no_mangle]
+pub unsafe fn uadd_u64x4(x: u64x4, y: u64x4) -> u64x4 {
+    // CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.uadd.sat.v4i64(<4 x i64> %{{x|0}}, <4 x i64> %{{y|1}})
+    simd_saturating_add(x, y)
+}
+
+// CHECK-LABEL: @uadd_u64x8
+#[no_mangle]
+pub unsafe fn uadd_u64x8(x: u64x8, y: u64x8) -> u64x8 {
+    // CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.uadd.sat.v8i64(<8 x i64> %{{x|0}}, <8 x i64> %{{y|1}})
+    simd_saturating_add(x, y)
+}
+
+// CHECK-LABEL: @uadd_u128x2
+#[no_mangle]
+pub unsafe fn uadd_u128x2(x: u128x2, y: u128x2) -> u128x2 {
+    // CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.uadd.sat.v2i128(<2 x i128> %{{x|0}}, <2 x i128> %{{y|1}})
+    simd_saturating_add(x, y)
+}
+
+// CHECK-LABEL: @uadd_u128x4
+#[no_mangle]
+pub unsafe fn uadd_u128x4(x: u128x4, y: u128x4) -> u128x4 {
+    // CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.uadd.sat.v4i128(<4 x i128> %{{x|0}}, <4 x i128> %{{y|1}})
+    simd_saturating_add(x, y)
+}
+
+// CHECK-LABEL: @ssub_i8x2
+#[no_mangle]
+pub unsafe fn ssub_i8x2(x: i8x2, y: i8x2) -> i8x2 {
+    // CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.ssub.sat.v2i8(<2 x i8> %{{x|0}}, <2 x i8> %{{y|1}})
+    simd_saturating_sub(x, y)
+}
+
+// CHECK-LABEL: @ssub_i8x4
+#[no_mangle]
+pub unsafe fn ssub_i8x4(x: i8x4, y: i8x4) -> i8x4 {
+    // CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.ssub.sat.v4i8(<4 x i8> %{{x|0}}, <4 x i8> %{{y|1}})
+    simd_saturating_sub(x, y)
+}
+
+// CHECK-LABEL: @ssub_i8x8
+#[no_mangle]
+pub unsafe fn ssub_i8x8(x: i8x8, y: i8x8) -> i8x8 {
+    // CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.ssub.sat.v8i8(<8 x i8> %{{x|0}}, <8 x i8> %{{y|1}})
+    simd_saturating_sub(x, y)
+}
+
+// CHECK-LABEL: @ssub_i8x16
+#[no_mangle]
+pub unsafe fn ssub_i8x16(x: i8x16, y: i8x16) -> i8x16 {
+    // CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.ssub.sat.v16i8(<16 x i8> %{{x|0}}, <16 x i8> %{{y|1}})
+    simd_saturating_sub(x, y)
+}
+
+// CHECK-LABEL: @ssub_i8x32
+#[no_mangle]
+pub unsafe fn ssub_i8x32(x: i8x32, y: i8x32) -> i8x32 {
+    // CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.ssub.sat.v32i8(<32 x i8> %{{x|0}}, <32 x i8> %{{y|1}})
+    simd_saturating_sub(x, y)
+}
+
+// CHECK-LABEL: @ssub_i8x64
+#[no_mangle]
+pub unsafe fn ssub_i8x64(x: i8x64, y: i8x64) -> i8x64 {
+    // CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.ssub.sat.v64i8(<64 x i8> %{{x|0}}, <64 x i8> %{{y|1}})
+    simd_saturating_sub(x, y)
+}
+
+// CHECK-LABEL: @ssub_i16x2
+#[no_mangle]
+pub unsafe fn ssub_i16x2(x: i16x2, y: i16x2) -> i16x2 {
+    // CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.ssub.sat.v2i16(<2 x i16> %{{x|0}}, <2 x i16> %{{y|1}})
+    simd_saturating_sub(x, y)
+}
+
+// CHECK-LABEL: @ssub_i16x4
+#[no_mangle]
+pub unsafe fn ssub_i16x4(x: i16x4, y: i16x4) -> i16x4 {
+    // CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.ssub.sat.v4i16(<4 x i16> %{{x|0}}, <4 x i16> %{{y|1}})
+    simd_saturating_sub(x, y)
+}
+
+// CHECK-LABEL: @ssub_i16x8
+#[no_mangle]
+pub unsafe fn ssub_i16x8(x: i16x8, y: i16x8) -> i16x8 {
+    // CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.ssub.sat.v8i16(<8 x i16> %{{x|0}}, <8 x i16> %{{y|1}})
+    simd_saturating_sub(x, y)
+}
+
+// CHECK-LABEL: @ssub_i16x16
+#[no_mangle]
+pub unsafe fn ssub_i16x16(x: i16x16, y: i16x16) -> i16x16 {
+    // CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.ssub.sat.v16i16(<16 x i16> %{{x|0}}, <16 x i16> %{{y|1}})
+    simd_saturating_sub(x, y)
+}
+
+// CHECK-LABEL: @ssub_i16x32
+#[no_mangle]
+pub unsafe fn ssub_i16x32(x: i16x32, y: i16x32) -> i16x32 {
+    // CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.ssub.sat.v32i16(<32 x i16> %{{x|0}}, <32 x i16> %{{y|1}})
+    simd_saturating_sub(x, y)
+}
+
+// CHECK-LABEL: @ssub_i32x2
+#[no_mangle]
+pub unsafe fn ssub_i32x2(x: i32x2, y: i32x2) -> i32x2 {
+    // CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.ssub.sat.v2i32(<2 x i32> %{{x|0}}, <2 x i32> %{{y|1}})
+    simd_saturating_sub(x, y)
+}
+
+// CHECK-LABEL: @ssub_i32x4
+#[no_mangle]
+pub unsafe fn ssub_i32x4(x: i32x4, y: i32x4) -> i32x4 {
+    // CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.ssub.sat.v4i32(<4 x i32> %{{x|0}}, <4 x i32> %{{y|1}})
+    simd_saturating_sub(x, y)
+}
+
+// CHECK-LABEL: @ssub_i32x8
+#[no_mangle]
+pub unsafe fn ssub_i32x8(x: i32x8, y: i32x8) -> i32x8 {
+    // CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.ssub.sat.v8i32(<8 x i32> %{{x|0}}, <8 x i32> %{{y|1}})
+    simd_saturating_sub(x, y)
+}
+
+// CHECK-LABEL: @ssub_i32x16
+#[no_mangle]
+pub unsafe fn ssub_i32x16(x: i32x16, y: i32x16) -> i32x16 {
+    // CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.ssub.sat.v16i32(<16 x i32> %{{x|0}}, <16 x i32> %{{y|1}})
+    simd_saturating_sub(x, y)
+}
+
+// CHECK-LABEL: @ssub_i64x2
+#[no_mangle]
+pub unsafe fn ssub_i64x2(x: i64x2, y: i64x2) -> i64x2 {
+    // CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.ssub.sat.v2i64(<2 x i64> %{{x|0}}, <2 x i64> %{{y|1}})
+    simd_saturating_sub(x, y)
+}
+
+// CHECK-LABEL: @ssub_i64x4
+#[no_mangle]
+pub unsafe fn ssub_i64x4(x: i64x4, y: i64x4) -> i64x4 {
+    // CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.ssub.sat.v4i64(<4 x i64> %{{x|0}}, <4 x i64> %{{y|1}})
+    simd_saturating_sub(x, y)
+}
+
+// CHECK-LABEL: @ssub_i64x8
+#[no_mangle]
+pub unsafe fn ssub_i64x8(x: i64x8, y: i64x8) -> i64x8 {
+    // CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.ssub.sat.v8i64(<8 x i64> %{{x|0}}, <8 x i64> %{{y|1}})
+    simd_saturating_sub(x, y)
+}
+
+// CHECK-LABEL: @ssub_i128x2
+#[no_mangle]
+pub unsafe fn ssub_i128x2(x: i128x2, y: i128x2) -> i128x2 {
+    // CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.ssub.sat.v2i128(<2 x i128> %{{x|0}}, <2 x i128> %{{y|1}})
+    simd_saturating_sub(x, y)
+}
+
+// CHECK-LABEL: @ssub_i128x4
+#[no_mangle]
+pub unsafe fn ssub_i128x4(x: i128x4, y: i128x4) -> i128x4 {
+    // CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.ssub.sat.v4i128(<4 x i128> %{{x|0}}, <4 x i128> %{{y|1}})
+    simd_saturating_sub(x, y)
+}
+
+// CHECK-LABEL: @usub_u8x2
+#[no_mangle]
+pub unsafe fn usub_u8x2(x: u8x2, y: u8x2) -> u8x2 {
+    // CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.usub.sat.v2i8(<2 x i8> %{{x|0}}, <2 x i8> %{{y|1}})
+    simd_saturating_sub(x, y)
+}
+
+// CHECK-LABEL: @usub_u8x4
+#[no_mangle]
+pub unsafe fn usub_u8x4(x: u8x4, y: u8x4) -> u8x4 {
+    // CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.usub.sat.v4i8(<4 x i8> %{{x|0}}, <4 x i8> %{{y|1}})
+    simd_saturating_sub(x, y)
+}
+
+// CHECK-LABEL: @usub_u8x8
+#[no_mangle]
+pub unsafe fn usub_u8x8(x: u8x8, y: u8x8) -> u8x8 {
+    // CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.usub.sat.v8i8(<8 x i8> %{{x|0}}, <8 x i8> %{{y|1}})
+    simd_saturating_sub(x, y)
+}
+
+// CHECK-LABEL: @usub_u8x16
+#[no_mangle]
+pub unsafe fn usub_u8x16(x: u8x16, y: u8x16) -> u8x16 {
+    // CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.usub.sat.v16i8(<16 x i8> %{{x|0}}, <16 x i8> %{{y|1}})
+    simd_saturating_sub(x, y)
+}
+
+// CHECK-LABEL: @usub_u8x32
+#[no_mangle]
+pub unsafe fn usub_u8x32(x: u8x32, y: u8x32) -> u8x32 {
+    // CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.usub.sat.v32i8(<32 x i8> %{{x|0}}, <32 x i8> %{{y|1}})
+    simd_saturating_sub(x, y)
+}
+
+// CHECK-LABEL: @usub_u8x64
+#[no_mangle]
+pub unsafe fn usub_u8x64(x: u8x64, y: u8x64) -> u8x64 {
+    // CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.usub.sat.v64i8(<64 x i8> %{{x|0}}, <64 x i8> %{{y|1}})
+    simd_saturating_sub(x, y)
+}
+
+// CHECK-LABEL: @usub_u16x2
+#[no_mangle]
+pub unsafe fn usub_u16x2(x: u16x2, y: u16x2) -> u16x2 {
+    // CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.usub.sat.v2i16(<2 x i16> %{{x|0}}, <2 x i16> %{{y|1}})
+    simd_saturating_sub(x, y)
+}
+
+// CHECK-LABEL: @usub_u16x4
+#[no_mangle]
+pub unsafe fn usub_u16x4(x: u16x4, y: u16x4) -> u16x4 {
+    // CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.usub.sat.v4i16(<4 x i16> %{{x|0}}, <4 x i16> %{{y|1}})
+    simd_saturating_sub(x, y)
+}
+
+// CHECK-LABEL: @usub_u16x8
+#[no_mangle]
+pub unsafe fn usub_u16x8(x: u16x8, y: u16x8) -> u16x8 {
+    // CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.usub.sat.v8i16(<8 x i16> %{{x|0}}, <8 x i16> %{{y|1}})
+    simd_saturating_sub(x, y)
+}
+
+// CHECK-LABEL: @usub_u16x16
+#[no_mangle]
+pub unsafe fn usub_u16x16(x: u16x16, y: u16x16) -> u16x16 {
+    // CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.usub.sat.v16i16(<16 x i16> %{{x|0}}, <16 x i16> %{{y|1}})
+    simd_saturating_sub(x, y)
+}
+
+// CHECK-LABEL: @usub_u16x32
+#[no_mangle]
+pub unsafe fn usub_u16x32(x: u16x32, y: u16x32) -> u16x32 {
+    // CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.usub.sat.v32i16(<32 x i16> %{{x|0}}, <32 x i16> %{{y|1}})
+    simd_saturating_sub(x, y)
+}
+
+// CHECK-LABEL: @usub_u32x2
+#[no_mangle]
+pub unsafe fn usub_u32x2(x: u32x2, y: u32x2) -> u32x2 {
+    // CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.usub.sat.v2i32(<2 x i32> %{{x|0}}, <2 x i32> %{{y|1}})
+    simd_saturating_sub(x, y)
+}
+
+// CHECK-LABEL: @usub_u32x4
+#[no_mangle]
+pub unsafe fn usub_u32x4(x: u32x4, y: u32x4) -> u32x4 {
+    // CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.usub.sat.v4i32(<4 x i32> %{{x|0}}, <4 x i32> %{{y|1}})
+    simd_saturating_sub(x, y)
+}
+
+// CHECK-LABEL: @usub_u32x8
+#[no_mangle]
+pub unsafe fn usub_u32x8(x: u32x8, y: u32x8) -> u32x8 {
+    // CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.usub.sat.v8i32(<8 x i32> %{{x|0}}, <8 x i32> %{{y|1}})
+    simd_saturating_sub(x, y)
+}
+
+// CHECK-LABEL: @usub_u32x16
+#[no_mangle]
+pub unsafe fn usub_u32x16(x: u32x16, y: u32x16) -> u32x16 {
+    // CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.usub.sat.v16i32(<16 x i32> %{{x|0}}, <16 x i32> %{{y|1}})
+    simd_saturating_sub(x, y)
+}
+
+// CHECK-LABEL: @usub_u64x2
+#[no_mangle]
+pub unsafe fn usub_u64x2(x: u64x2, y: u64x2) -> u64x2 {
+    // CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.usub.sat.v2i64(<2 x i64> %{{x|0}}, <2 x i64> %{{y|1}})
+    simd_saturating_sub(x, y)
+}
+
+// CHECK-LABEL: @usub_u64x4
+#[no_mangle]
+pub unsafe fn usub_u64x4(x: u64x4, y: u64x4) -> u64x4 {
+    // CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.usub.sat.v4i64(<4 x i64> %{{x|0}}, <4 x i64> %{{y|1}})
+    simd_saturating_sub(x, y)
+}
+
+// CHECK-LABEL: @usub_u64x8
+#[no_mangle]
+pub unsafe fn usub_u64x8(x: u64x8, y: u64x8) -> u64x8 {
+    // CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.usub.sat.v8i64(<8 x i64> %{{x|0}}, <8 x i64> %{{y|1}})
+    simd_saturating_sub(x, y)
+}
+
+// CHECK-LABEL: @usub_u128x2
+#[no_mangle]
+pub unsafe fn usub_u128x2(x: u128x2, y: u128x2) -> u128x2 {
+    // CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.usub.sat.v2i128(<2 x i128> %{{x|0}}, <2 x i128> %{{y|1}})
+    simd_saturating_sub(x, y)
+}
+
+// CHECK-LABEL: @usub_u128x4
+#[no_mangle]
+pub unsafe fn usub_u128x4(x: u128x4, y: u128x4) -> u128x4 {
+    // CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.usub.sat.v4i128(<4 x i128> %{{x|0}}, <4 x i128> %{{y|1}})
+    simd_saturating_sub(x, y)
+}
diff --git a/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-bitmask.rs b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-bitmask.rs
new file mode 100644
index 00000000000..294262d8152
--- /dev/null
+++ b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-bitmask.rs
@@ -0,0 +1,48 @@
+//@ compile-flags: -C no-prepopulate-passes
+//
+
+#![crate_type = "lib"]
+#![feature(repr_simd, core_intrinsics)]
+#![allow(non_camel_case_types)]
+
+#[path = "../../auxiliary/minisimd.rs"]
+mod minisimd;
+use minisimd::*;
+
+use std::intrinsics::simd::simd_bitmask;
+
+// NOTE(eddyb) `%{{x|1}}` is used because on some targets (e.g. WASM)
+// SIMD vectors are passed directly, resulting in `%x` being a vector,
+// while on others they're passed indirectly, resulting in `%x` being
+// a pointer to a vector, and `%1` a vector loaded from that pointer.
+// This is controlled by the target spec option `simd_types_indirect`.
+
+// CHECK-LABEL: @bitmask_int
+#[no_mangle]
+pub unsafe fn bitmask_int(x: i32x2) -> u8 {
+    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{x|1}}, {{<i32 31, i32 31>|splat \(i32 31\)}}
+    // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
+    // CHECK: [[C:%[0-9]+]] = bitcast <2 x i1> [[B]] to i2
+    // CHECK: %{{[0-9]+}} = zext i2 [[C]] to i8
+    simd_bitmask(x)
+}
+
+// CHECK-LABEL: @bitmask_uint
+#[no_mangle]
+pub unsafe fn bitmask_uint(x: u32x2) -> u8 {
+    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{x|1}}, {{<i32 31, i32 31>|splat \(i32 31\)}}
+    // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
+    // CHECK: [[C:%[0-9]+]] = bitcast <2 x i1> [[B]] to i2
+    // CHECK: %{{[0-9]+}} = zext i2 [[C]] to i8
+    simd_bitmask(x)
+}
+
+// CHECK-LABEL: @bitmask_int16
+#[no_mangle]
+pub unsafe fn bitmask_int16(x: i8x16) -> u16 {
+    // CHECK: [[A:%[0-9]+]] = lshr <16 x i8> %{{x|1|2}}, {{<i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7>|splat \(i8 7\)}}
+    // CHECK: [[B:%[0-9]+]] = trunc <16 x i8> [[A]] to <16 x i1>
+    // CHECK: %{{[0-9]+}} = bitcast <16 x i1> [[B]] to i16
+    // CHECK-NOT: zext
+    simd_bitmask(x)
+}
diff --git a/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-gather.rs b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-gather.rs
new file mode 100644
index 00000000000..690bfb432f9
--- /dev/null
+++ b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-gather.rs
@@ -0,0 +1,55 @@
+//
+
+//@ compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+#![feature(repr_simd, core_intrinsics)]
+#![allow(non_camel_case_types)]
+
+#[path = "../../auxiliary/minisimd.rs"]
+mod minisimd;
+use minisimd::*;
+
+use std::intrinsics::simd::simd_gather;
+
+pub type Vec2<T> = Simd<T, 2>;
+pub type Vec4<T> = Simd<T, 4>;
+
+// CHECK-LABEL: @gather_f32x2
+#[no_mangle]
+pub unsafe fn gather_f32x2(
+    pointers: Vec2<*const f32>,
+    mask: Vec2<i32>,
+    values: Vec2<f32>,
+) -> Vec2<f32> {
+    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{<i32 31, i32 31>|splat \(i32 31\)}}
+    // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
+    // CHECK: call <2 x float> @llvm.masked.gather.v2f32.v2p0(<2 x ptr> {{.*}}, i32 {{.*}}, <2 x i1> [[B]], <2 x float> {{.*}})
+    simd_gather(values, pointers, mask)
+}
+
+// CHECK-LABEL: @gather_f32x2_unsigned
+#[no_mangle]
+pub unsafe fn gather_f32x2_unsigned(
+    pointers: Vec2<*const f32>,
+    mask: Vec2<u32>,
+    values: Vec2<f32>,
+) -> Vec2<f32> {
+    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{<i32 31, i32 31>|splat \(i32 31\)}}
+    // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
+    // CHECK: call <2 x float> @llvm.masked.gather.v2f32.v2p0(<2 x ptr> {{.*}}, i32 {{.*}}, <2 x i1> [[B]], <2 x float> {{.*}})
+    simd_gather(values, pointers, mask)
+}
+
+// CHECK-LABEL: @gather_pf32x2
+#[no_mangle]
+pub unsafe fn gather_pf32x2(
+    pointers: Vec2<*const *const f32>,
+    mask: Vec2<i32>,
+    values: Vec2<*const f32>,
+) -> Vec2<*const f32> {
+    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{<i32 31, i32 31>|splat \(i32 31\)}}
+    // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
+    // CHECK: call <2 x ptr> @llvm.masked.gather.v2p0.v2p0(<2 x ptr> {{.*}}, i32 {{.*}}, <2 x i1> [[B]], <2 x ptr> {{.*}})
+    simd_gather(values, pointers, mask)
+}
diff --git a/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-masked-load.rs b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-masked-load.rs
new file mode 100644
index 00000000000..fda315dc66c
--- /dev/null
+++ b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-masked-load.rs
@@ -0,0 +1,49 @@
+//@ compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+#![feature(repr_simd, core_intrinsics)]
+#![allow(non_camel_case_types)]
+
+#[path = "../../auxiliary/minisimd.rs"]
+mod minisimd;
+use minisimd::*;
+
+use std::intrinsics::simd::simd_masked_load;
+
+pub type Vec2<T> = Simd<T, 2>;
+pub type Vec4<T> = Simd<T, 4>;
+
+// CHECK-LABEL: @load_f32x2
+#[no_mangle]
+pub unsafe fn load_f32x2(mask: Vec2<i32>, pointer: *const f32, values: Vec2<f32>) -> Vec2<f32> {
+    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{<i32 31, i32 31>|splat \(i32 31\)}}
+    // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
+    // CHECK: call <2 x float> @llvm.masked.load.v2f32.p0(ptr {{.*}}, i32 4, <2 x i1> [[B]], <2 x float> {{.*}})
+    simd_masked_load(mask, pointer, values)
+}
+
+// CHECK-LABEL: @load_f32x2_unsigned
+#[no_mangle]
+pub unsafe fn load_f32x2_unsigned(
+    mask: Vec2<u32>,
+    pointer: *const f32,
+    values: Vec2<f32>,
+) -> Vec2<f32> {
+    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{<i32 31, i32 31>|splat \(i32 31\)}}
+    // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
+    // CHECK: call <2 x float> @llvm.masked.load.v2f32.p0(ptr {{.*}}, i32 4, <2 x i1> [[B]], <2 x float> {{.*}})
+    simd_masked_load(mask, pointer, values)
+}
+
+// CHECK-LABEL: @load_pf32x4
+#[no_mangle]
+pub unsafe fn load_pf32x4(
+    mask: Vec4<i32>,
+    pointer: *const *const f32,
+    values: Vec4<*const f32>,
+) -> Vec4<*const f32> {
+    // CHECK: [[A:%[0-9]+]] = lshr <4 x i32> {{.*}}, {{<i32 31, i32 31, i32 31, i32 31>|splat \(i32 31\)}}
+    // CHECK: [[B:%[0-9]+]] = trunc <4 x i32> [[A]] to <4 x i1>
+    // CHECK: call <4 x ptr> @llvm.masked.load.v4p0.p0(ptr {{.*}}, i32 {{.*}}, <4 x i1> [[B]], <4 x ptr> {{.*}})
+    simd_masked_load(mask, pointer, values)
+}
diff --git a/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-masked-store.rs b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-masked-store.rs
new file mode 100644
index 00000000000..6ca7388d464
--- /dev/null
+++ b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-masked-store.rs
@@ -0,0 +1,41 @@
+//@ compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+#![feature(repr_simd, core_intrinsics)]
+#![allow(non_camel_case_types)]
+
+#[path = "../../auxiliary/minisimd.rs"]
+mod minisimd;
+use minisimd::*;
+
+use std::intrinsics::simd::simd_masked_store;
+
+pub type Vec2<T> = Simd<T, 2>;
+pub type Vec4<T> = Simd<T, 4>;
+
+// CHECK-LABEL: @store_f32x2
+#[no_mangle]
+pub unsafe fn store_f32x2(mask: Vec2<i32>, pointer: *mut f32, values: Vec2<f32>) {
+    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{<i32 31, i32 31>|splat \(i32 31\)}}
+    // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
+    // CHECK: call void @llvm.masked.store.v2f32.p0(<2 x float> {{.*}}, ptr {{.*}}, i32 4, <2 x i1> [[B]])
+    simd_masked_store(mask, pointer, values)
+}
+
+// CHECK-LABEL: @store_f32x2_unsigned
+#[no_mangle]
+pub unsafe fn store_f32x2_unsigned(mask: Vec2<u32>, pointer: *mut f32, values: Vec2<f32>) {
+    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{<i32 31, i32 31>|splat \(i32 31\)}}
+    // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
+    // CHECK: call void @llvm.masked.store.v2f32.p0(<2 x float> {{.*}}, ptr {{.*}}, i32 4, <2 x i1> [[B]])
+    simd_masked_store(mask, pointer, values)
+}
+
+// CHECK-LABEL: @store_pf32x4
+#[no_mangle]
+pub unsafe fn store_pf32x4(mask: Vec4<i32>, pointer: *mut *const f32, values: Vec4<*const f32>) {
+    // CHECK: [[A:%[0-9]+]] = lshr <4 x i32> {{.*}}, {{<i32 31, i32 31, i32 31, i32 31>|splat \(i32 31\)}}
+    // CHECK: [[B:%[0-9]+]] = trunc <4 x i32> [[A]] to <4 x i1>
+    // CHECK: call void @llvm.masked.store.v4p0.p0(<4 x ptr> {{.*}}, ptr {{.*}}, i32 {{.*}}, <4 x i1> [[B]])
+    simd_masked_store(mask, pointer, values)
+}
diff --git a/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-scatter.rs b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-scatter.rs
new file mode 100644
index 00000000000..743652966e1
--- /dev/null
+++ b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-scatter.rs
@@ -0,0 +1,47 @@
+//
+
+//@ compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+#![feature(repr_simd, core_intrinsics)]
+#![allow(non_camel_case_types)]
+
+#[path = "../../auxiliary/minisimd.rs"]
+mod minisimd;
+use minisimd::*;
+
+use std::intrinsics::simd::simd_scatter;
+
+pub type Vec2<T> = Simd<T, 2>;
+pub type Vec4<T> = Simd<T, 4>;
+
+// CHECK-LABEL: @scatter_f32x2
+#[no_mangle]
+pub unsafe fn scatter_f32x2(pointers: Vec2<*mut f32>, mask: Vec2<i32>, values: Vec2<f32>) {
+    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{<i32 31, i32 31>|splat \(i32 31\)}}
+    // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
+    // CHECK: call void @llvm.masked.scatter.v2f32.v2p0(<2 x float> {{.*}}, <2 x ptr> {{.*}}, i32 {{.*}}, <2 x i1> [[B]]
+    simd_scatter(values, pointers, mask)
+}
+
+// CHECK-LABEL: @scatter_f32x2_unsigned
+#[no_mangle]
+pub unsafe fn scatter_f32x2_unsigned(pointers: Vec2<*mut f32>, mask: Vec2<u32>, values: Vec2<f32>) {
+    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{<i32 31, i32 31>|splat \(i32 31\)}}
+    // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
+    // CHECK: call void @llvm.masked.scatter.v2f32.v2p0(<2 x float> {{.*}}, <2 x ptr> {{.*}}, i32 {{.*}}, <2 x i1> [[B]]
+    simd_scatter(values, pointers, mask)
+}
+
+// CHECK-LABEL: @scatter_pf32x2
+#[no_mangle]
+pub unsafe fn scatter_pf32x2(
+    pointers: Vec2<*mut *const f32>,
+    mask: Vec2<i32>,
+    values: Vec2<*const f32>,
+) {
+    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{<i32 31, i32 31>|splat \(i32 31\)}}
+    // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
+    // CHECK: call void @llvm.masked.scatter.v2p0.v2p0(<2 x ptr> {{.*}}, <2 x ptr> {{.*}}, i32 {{.*}}, <2 x i1> [[B]]
+    simd_scatter(values, pointers, mask)
+}
diff --git a/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-select.rs b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-select.rs
new file mode 100644
index 00000000000..2c0bad21f44
--- /dev/null
+++ b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-select.rs
@@ -0,0 +1,48 @@
+//@ compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+#![feature(repr_simd, core_intrinsics)]
+#![allow(non_camel_case_types)]
+
+#[path = "../../auxiliary/minisimd.rs"]
+mod minisimd;
+use minisimd::*;
+
+use std::intrinsics::simd::{simd_select, simd_select_bitmask};
+
+pub type b8x4 = i8x4;
+
+// CHECK-LABEL: @select_m8
+#[no_mangle]
+pub unsafe fn select_m8(m: b8x4, a: f32x4, b: f32x4) -> f32x4 {
+    // CHECK: [[A:%[0-9]+]] = lshr <4 x i8> %{{.*}}, {{<i8 7, i8 7, i8 7, i8 7>|splat \(i8 7\)}}
+    // CHECK: [[B:%[0-9]+]] = trunc <4 x i8> [[A]] to <4 x i1>
+    // CHECK: select <4 x i1> [[B]]
+    simd_select(m, a, b)
+}
+
+// CHECK-LABEL: @select_m32
+#[no_mangle]
+pub unsafe fn select_m32(m: i32x4, a: f32x4, b: f32x4) -> f32x4 {
+    // CHECK: [[A:%[0-9]+]] = lshr <4 x i32> %{{.*}}, {{<i32 31, i32 31, i32 31, i32 31>|splat \(i32 31\)}}
+    // CHECK: [[B:%[0-9]+]] = trunc <4 x i32> [[A]] to <4 x i1>
+    // CHECK: select <4 x i1> [[B]]
+    simd_select(m, a, b)
+}
+
+// CHECK-LABEL: @select_m32_unsigned
+#[no_mangle]
+pub unsafe fn select_m32_unsigned(m: u32x4, a: f32x4, b: f32x4) -> f32x4 {
+    // CHECK: [[A:%[0-9]+]] = lshr <4 x i32> %{{.*}}, {{<i32 31, i32 31, i32 31, i32 31>|splat \(i32 31\)}}
+    // CHECK: [[B:%[0-9]+]] = trunc <4 x i32> [[A]] to <4 x i1>
+    // CHECK: select <4 x i1> [[B]]
+    simd_select(m, a, b)
+}
+
+// CHECK-LABEL: @select_bitmask
+#[no_mangle]
+pub unsafe fn select_bitmask(m: i8, a: f32x8, b: f32x8) -> f32x8 {
+    // CHECK: [[A:%[0-9]+]] = bitcast i8 {{.*}} to <8 x i1>
+    // CHECK: select <8 x i1> [[A]]
+    simd_select_bitmask(m, a, b)
+}
diff --git a/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-mask-reduce.rs b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-mask-reduce.rs
new file mode 100644
index 00000000000..79f00a6ed60
--- /dev/null
+++ b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-mask-reduce.rs
@@ -0,0 +1,60 @@
+//@ compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+#![feature(repr_simd, core_intrinsics)]
+#![allow(non_camel_case_types)]
+
+#[path = "../../auxiliary/minisimd.rs"]
+mod minisimd;
+use minisimd::*;
+
+use std::intrinsics::simd::{simd_reduce_all, simd_reduce_any};
+
+pub type mask32x2 = Simd<i32, 2>;
+pub type mask8x16 = Simd<i8, 16>;
+
+// NOTE(eddyb) `%{{x|1}}` is used because on some targets (e.g. WASM)
+// SIMD vectors are passed directly, resulting in `%x` being a vector,
+// while on others they're passed indirectly, resulting in `%x` being
+// a pointer to a vector, and `%1` a vector loaded from that pointer.
+// This is controlled by the target spec option `simd_types_indirect`.
+
+// CHECK-LABEL: @reduce_any_32x2
+#[no_mangle]
+pub unsafe fn reduce_any_32x2(x: mask32x2) -> bool {
+    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{x|1}}, {{<i32 31, i32 31>|splat \(i32 31\)}}
+    // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
+    // CHECK: [[C:%[0-9]+]] = call i1 @llvm.vector.reduce.or.v2i1(<2 x i1> [[B]])
+    // CHECK: %{{[0-9]+}} = zext i1 [[C]] to i8
+    simd_reduce_any(x)
+}
+
+// CHECK-LABEL: @reduce_all_32x2
+#[no_mangle]
+pub unsafe fn reduce_all_32x2(x: mask32x2) -> bool {
+    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{x|1}}, {{<i32 31, i32 31>|splat \(i32 31\)}}
+    // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
+    // CHECK: [[C:%[0-9]+]] = call i1 @llvm.vector.reduce.and.v2i1(<2 x i1> [[B]])
+    // CHECK: %{{[0-9]+}} = zext i1 [[C]] to i8
+    simd_reduce_all(x)
+}
+
+// CHECK-LABEL: @reduce_any_8x16
+#[no_mangle]
+pub unsafe fn reduce_any_8x16(x: mask8x16) -> bool {
+    // CHECK: [[A:%[0-9]+]] = lshr <16 x i8> %{{x|1}}, {{<i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7>|splat \(i8 7\)}}
+    // CHECK: [[B:%[0-9]+]] = trunc <16 x i8> [[A]] to <16 x i1>
+    // CHECK: [[C:%[0-9]+]] = call i1 @llvm.vector.reduce.or.v16i1(<16 x i1> [[B]])
+    // CHECK: %{{[0-9]+}} = zext i1 [[C]] to i8
+    simd_reduce_any(x)
+}
+
+// CHECK-LABEL: @reduce_all_8x16
+#[no_mangle]
+pub unsafe fn reduce_all_8x16(x: mask8x16) -> bool {
+    // CHECK: [[A:%[0-9]+]] = lshr <16 x i8> %{{x|1}}, {{<i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7>|splat \(i8 7\)}}
+    // CHECK: [[B:%[0-9]+]] = trunc <16 x i8> [[A]] to <16 x i1>
+    // CHECK: [[C:%[0-9]+]] = call i1 @llvm.vector.reduce.and.v16i1(<16 x i1> [[B]])
+    // CHECK: %{{[0-9]+}} = zext i1 [[C]] to i8
+    simd_reduce_all(x)
+}
diff --git a/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-transmute-array.rs b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-transmute-array.rs
new file mode 100644
index 00000000000..05c2f7e1bdf
--- /dev/null
+++ b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-transmute-array.rs
@@ -0,0 +1,58 @@
+//
+//@ compile-flags: -C no-prepopulate-passes
+// 32bit MSVC does not align things properly so we suppress high alignment annotations (#112480)
+//@ ignore-i686-pc-windows-msvc
+//@ ignore-i686-pc-windows-gnu
+
+#![crate_type = "lib"]
+#![allow(non_camel_case_types)]
+#![feature(repr_simd, core_intrinsics)]
+
+#[path = "../../auxiliary/minisimd.rs"]
+mod minisimd;
+use minisimd::*;
+
+pub type S<const N: usize> = Simd<f32, N>;
+pub type T = Simd<f32, 4>;
+
+// CHECK-LABEL: @array_align(
+#[no_mangle]
+pub fn array_align() -> usize {
+    // CHECK: ret [[USIZE:i[0-9]+]] [[ARRAY_ALIGN:[0-9]+]]
+    const { std::mem::align_of::<f32>() }
+}
+
+// CHECK-LABEL: @vector_align(
+#[no_mangle]
+pub fn vector_align() -> usize {
+    // CHECK: ret [[USIZE]] [[VECTOR_ALIGN:[0-9]+]]
+    const { std::mem::align_of::<T>() }
+}
+
+// CHECK-LABEL: @build_array_s
+#[no_mangle]
+pub fn build_array_s(x: [f32; 4]) -> S<4> {
+    // CHECK: call void @llvm.memcpy.{{.+}}({{.*}} align [[VECTOR_ALIGN]] {{.*}} align [[ARRAY_ALIGN]] {{.*}}, [[USIZE]] 16, i1 false)
+    Simd(x)
+}
+
+// CHECK-LABEL: @build_array_transmute_s
+#[no_mangle]
+pub fn build_array_transmute_s(x: [f32; 4]) -> S<4> {
+    // CHECK: call void @llvm.memcpy.{{.+}}({{.*}} align [[VECTOR_ALIGN]] {{.*}} align [[ARRAY_ALIGN]] {{.*}}, [[USIZE]] 16, i1 false)
+    unsafe { std::mem::transmute(x) }
+}
+
+// CHECK-LABEL: @build_array_t
+#[no_mangle]
+pub fn build_array_t(x: [f32; 4]) -> T {
+    // CHECK: call void @llvm.memcpy.{{.+}}({{.*}} align [[VECTOR_ALIGN]] {{.*}} align [[ARRAY_ALIGN]] {{.*}}, [[USIZE]] 16, i1 false)
+    Simd(x)
+}
+
+// CHECK-LABEL: @build_array_transmute_t
+#[no_mangle]
+pub fn build_array_transmute_t(x: [f32; 4]) -> T {
+    // CHECK: call void @llvm.memcpy.{{.+}}({{.*}} align [[VECTOR_ALIGN]] {{.*}} align [[ARRAY_ALIGN]] {{.*}}, [[USIZE]] 16, i1 false)
+    unsafe { std::mem::transmute(x) }
+}
diff --git a/tests/codegen-llvm/simd/aggregate-simd.rs b/tests/codegen-llvm/simd/aggregate-simd.rs
new file mode 100644
index 00000000000..57a301d634c
--- /dev/null
+++ b/tests/codegen-llvm/simd/aggregate-simd.rs
@@ -0,0 +1,102 @@
+//@ compile-flags: -C opt-level=3 -C no-prepopulate-passes
+//@ only-64bit
+
+#![feature(core_intrinsics, repr_simd)]
+#![no_std]
+#![crate_type = "lib"]
+
+#[path = "../../auxiliary/minisimd.rs"]
+mod minisimd;
+use core::intrinsics::simd::{simd_add, simd_extract};
+
+use minisimd::*;
+
+#[repr(transparent)]
+pub struct Transparent<T>(T);
+
+// These tests don't actually care about the add/extract, but it ensures the
+// aggregated temporaries are only used in potentially-SSA ways.
+
+#[no_mangle]
+pub fn simd_aggregate_pot(x: [u32; 4], y: [u32; 4]) -> u32 {
+    // CHECK-LABEL: simd_aggregate_pot
+    // CHECK: %a = load <4 x i32>, ptr %x, align 4
+    // CHECK: %b = load <4 x i32>, ptr %y, align 4
+    // CHECK: add <4 x i32> %a, %b
+
+    unsafe {
+        let a = Simd(x);
+        let b = Simd(y);
+        let c = simd_add(a, b);
+        simd_extract(c, 1)
+    }
+}
+
+#[no_mangle]
+pub fn simd_aggregate_npot(x: [u32; 7], y: [u32; 7]) -> u32 {
+    // CHECK-LABEL: simd_aggregate_npot
+    // CHECK: %a = load <7 x i32>, ptr %x, align 4
+    // CHECK: %b = load <7 x i32>, ptr %y, align 4
+    // CHECK: add <7 x i32> %a, %b
+
+    unsafe {
+        let a = Simd(x);
+        let b = Simd(y);
+        let c = simd_add(a, b);
+        simd_extract(c, 1)
+    }
+}
+
+#[no_mangle]
+pub fn packed_simd_aggregate_pot(x: [u32; 4], y: [u32; 4]) -> u32 {
+    // CHECK-LABEL: packed_simd_aggregate_pot
+    // CHECK: %a = load <4 x i32>, ptr %x, align 4
+    // CHECK: %b = load <4 x i32>, ptr %y, align 4
+    // CHECK: add <4 x i32> %a, %b
+
+    unsafe {
+        let a = PackedSimd(x);
+        let b = PackedSimd(y);
+        let c = simd_add(a, b);
+        simd_extract(c, 1)
+    }
+}
+
+#[no_mangle]
+pub fn packed_simd_aggregate_npot(x: [u32; 7], y: [u32; 7]) -> u32 {
+    // CHECK-LABEL: packed_simd_aggregate_npot
+    // CHECK: %b = alloca [28 x i8], align 4
+    // CHECK: %a = alloca [28 x i8], align 4
+    // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %a, ptr align 4 %x, i64 28, i1 false)
+    // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %b, ptr align 4 %y, i64 28, i1 false)
+    // CHECK: %[[TEMPA:.+]] = load <7 x i32>, ptr %a, align 4
+    // CHECK: %[[TEMPB:.+]] = load <7 x i32>, ptr %b, align 4
+    // CHECK: add <7 x i32> %[[TEMPA]], %[[TEMPB]]
+
+    unsafe {
+        let a = PackedSimd(x);
+        let b = PackedSimd(y);
+        let c = simd_add(a, b);
+        simd_extract(c, 1)
+    }
+}
+
+#[no_mangle]
+pub fn transparent_simd_aggregate(x: [u32; 4]) -> u32 {
+    // The transparent wrapper can just use the same SSA value as its field.
+    // No extra processing or spilling needed.
+
+    // CHECK-LABEL: transparent_simd_aggregate
+    // CHECK-NOT: alloca
+    // CHECK: %[[RET:.+]] = alloca [4 x i8]
+    // CHECK-NOT: alloca
+    // CHECK: %a = load <4 x i32>, ptr %x, align 4
+    // CHECK: %[[TEMP:.+]] = extractelement <4 x i32> %a, i32 1
+    // CHECK: store i32 %[[TEMP]], ptr %[[RET]]
+
+    unsafe {
+        let a = Simd(x);
+        let b = Transparent(a);
+        simd_extract(b.0, 1)
+    }
+}
diff --git a/tests/codegen-llvm/simd/extract-insert-dyn.rs b/tests/codegen-llvm/simd/extract-insert-dyn.rs
new file mode 100644
index 00000000000..729f0145314
--- /dev/null
+++ b/tests/codegen-llvm/simd/extract-insert-dyn.rs
@@ -0,0 +1,121 @@
+//@compile-flags: -C opt-level=3 -C no-prepopulate-passes
+
+#![feature(
+    core_intrinsics,
+    repr_simd,
+    arm_target_feature,
+    mips_target_feature,
+    s390x_target_feature
+)]
+#![no_std]
+#![crate_type = "lib"]
+#![allow(non_camel_case_types)]
+
+// Test that `core::intrinsics::simd::{simd_extract_dyn, simd_insert_dyn}`
+// lower to an LLVM extractelement or insertelement operation.
+
+use core::intrinsics::simd::{simd_extract, simd_extract_dyn, simd_insert, simd_insert_dyn};
+
+#[repr(simd)]
+#[derive(Clone, Copy)]
+pub struct u32x16([u32; 16]);
+
+#[repr(simd)]
+#[derive(Clone, Copy)]
+pub struct i8x16([i8; 16]);
+
+// CHECK-LABEL: dyn_simd_extract
+// CHECK: extractelement <16 x i8> %x, i32 %idx
+#[no_mangle]
+#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))]
+#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))]
+#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))]
+#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))]
+#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))]
+unsafe extern "C" fn dyn_simd_extract(x: i8x16, idx: u32) -> i8 {
+    simd_extract_dyn(x, idx)
+}
+
+// CHECK-LABEL: literal_dyn_simd_extract
+// CHECK: extractelement <16 x i8> %x, i32 7
+#[no_mangle]
+#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))]
+#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))]
+#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))]
+#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))]
+#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))]
+unsafe extern "C" fn literal_dyn_simd_extract(x: i8x16) -> i8 {
+    simd_extract_dyn(x, 7)
+}
+
+// CHECK-LABEL: const_dyn_simd_extract
+// CHECK: extractelement <16 x i8> %x, i32 7
+#[no_mangle]
+#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))]
+#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))]
+#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))]
+#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))]
+#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))]
+unsafe extern "C" fn const_dyn_simd_extract(x: i8x16) -> i8 {
+    simd_extract_dyn(x, const { 3 + 4 })
+}
+
+// CHECK-LABEL: const_simd_extract
+// CHECK: extractelement <16 x i8> %x, i32 7
+#[no_mangle]
+#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))]
+#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))]
+#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))]
+#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))]
+#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))]
+unsafe extern "C" fn const_simd_extract(x: i8x16) -> i8 {
+    simd_extract(x, const { 3 + 4 })
+}
+
+// CHECK-LABEL: dyn_simd_insert
+// CHECK: insertelement <16 x i8> %x, i8 %e, i32 %idx
+#[no_mangle]
+#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))]
+#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))]
+#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))]
+#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))]
+#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))]
+unsafe extern "C" fn dyn_simd_insert(x: i8x16, e: i8, idx: u32) -> i8x16 {
+    simd_insert_dyn(x, idx, e)
+}
+
+// CHECK-LABEL: literal_dyn_simd_insert
+// CHECK: insertelement <16 x i8> %x, i8 %e, i32 7
+#[no_mangle]
+#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))]
+#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))]
+#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))]
+#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))]
+#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))]
+unsafe extern "C" fn literal_dyn_simd_insert(x: i8x16, e: i8) -> i8x16 {
+    simd_insert_dyn(x, 7, e)
+}
+
+// CHECK-LABEL: const_dyn_simd_insert
+// CHECK: insertelement <16 x i8> %x, i8 %e, i32 7
+#[no_mangle]
+#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))]
+#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))]
+#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))]
+#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))]
+#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))]
+unsafe extern "C" fn const_dyn_simd_insert(x: i8x16, e: i8) -> i8x16 {
+    simd_insert_dyn(x, const { 3 + 4 }, e)
+}
+
+// CHECK-LABEL: const_simd_insert
+// CHECK: insertelement <16 x i8> %x, i8 %e, i32 7
+#[no_mangle]
+#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))]
+#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))]
+#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))]
+#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))]
+#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))]
+unsafe extern "C" fn const_simd_insert(x: i8x16, e: i8) -> i8x16 {
+    simd_insert(x, const { 3 + 4 }, e)
+}
diff --git a/tests/codegen-llvm/simd/packed-simd-alignment.rs b/tests/codegen-llvm/simd/packed-simd-alignment.rs
new file mode 100644
index 00000000000..53e88d8e5cf
--- /dev/null
+++ b/tests/codegen-llvm/simd/packed-simd-alignment.rs
@@ -0,0 +1,44 @@
+//@ compile-flags: -Cno-prepopulate-passes
+
+#![crate_type = "lib"]
+#![feature(repr_simd, core_intrinsics)]
+// make sure that codegen emits correctly-aligned loads and stores for repr(packed, simd) types
+// the alignment of a load should be no less than T, and no more than the size of the vector type
+use std::intrinsics::simd as intrinsics;
+
+#[derive(Copy, Clone)]
+#[repr(packed, simd)]
+struct f32x3([f32; 3]);
+
+#[derive(Copy, Clone)]
+#[repr(packed, simd)]
+struct f32x4([f32; 4]);
+
+// CHECK-LABEL: load_f32x3
+#[no_mangle]
+pub fn load_f32x3(floats: &f32x3) -> f32x3 {
+    // FIXME: Is a memcpy really the best we can do?
+    // CHECK: @llvm.memcpy.{{.*}}ptr align 4 {{.*}}ptr align 4
+    *floats
+}
+
+// CHECK-LABEL: load_f32x4
+#[no_mangle]
+pub fn load_f32x4(floats: &f32x4) -> f32x4 {
+    // CHECK: load <4 x float>, ptr %{{[a-z0-9_]*}}, align {{4|8|16}}
+    *floats
+}
+
+// CHECK-LABEL: add_f32x3
+#[no_mangle]
+pub fn add_f32x3(x: f32x3, y: f32x3) -> f32x3 {
+    // CHECK: load <3 x float>, ptr %{{[a-z0-9_]*}}, align 4
+    unsafe { intrinsics::simd_add(x, y) }
+}
+
+// CHECK-LABEL: add_f32x4
+#[no_mangle]
+pub fn add_f32x4(x: f32x4, y: f32x4) -> f32x4 {
+    // CHECK: load <4 x float>, ptr %{{[a-z0-9_]*}}, align {{4|8|16}}
+    unsafe { intrinsics::simd_add(x, y) }
+}
diff --git a/tests/codegen-llvm/simd/packed-simd.rs b/tests/codegen-llvm/simd/packed-simd.rs
new file mode 100644
index 00000000000..70c03fcc955
--- /dev/null
+++ b/tests/codegen-llvm/simd/packed-simd.rs
@@ -0,0 +1,56 @@
+//@ revisions:opt3 noopt
+//@ only-x86_64
+//@[opt3] compile-flags: -Copt-level=3
+//@[noopt] compile-flags: -Cno-prepopulate-passes
+
+#![crate_type = "lib"]
+#![no_std]
+#![feature(repr_simd, core_intrinsics)]
+use core::intrinsics::simd as intrinsics;
+use core::{mem, ptr};
+
+#[path = "../../auxiliary/minisimd.rs"]
+mod minisimd;
+use minisimd::{PackedSimd, Simd as FullSimd};
+
+// Test codegen for not only "packed" but also "fully aligned" SIMD types, and conversion between
+// them. A repr(packed,simd) type with 3 elements can't exceed its element alignment, whereas the
+// same type as repr(simd) will instead have padding.
+
+// non-powers-of-two have padding and need to be expanded to full vectors
+fn load<T, const N: usize>(v: PackedSimd<T, N>) -> FullSimd<T, N> {
+    unsafe {
+        let mut tmp = mem::MaybeUninit::<FullSimd<T, N>>::uninit();
+        ptr::copy_nonoverlapping(&v as *const _, tmp.as_mut_ptr().cast(), 1);
+        tmp.assume_init()
+    }
+}
+
+// CHECK-LABEL: square_packed_full
+// CHECK-SAME: ptr{{[a-z_ ]*}} sret([[RET_TYPE:[^)]+]]) [[RET_ALIGN:align (8|16)]]{{[^%]*}} [[RET_VREG:%[_0-9]*]]
+// CHECK-SAME: ptr{{[a-z_ ]*}} align 4
+#[no_mangle]
+pub fn square_packed_full(x: PackedSimd<f32, 3>) -> FullSimd<f32, 3> {
+    // CHECK-NEXT: start
+    // noopt: alloca [[RET_TYPE]], [[RET_ALIGN]]
+    // CHECK: load <3 x float>
+    let x = load(x);
+    // CHECK: [[VREG:%[a-z0-9_]+]] = fmul <3 x float>
+    // CHECK-NEXT: store <3 x float> [[VREG]], ptr [[RET_VREG]], [[RET_ALIGN]]
+    // CHECK-NEXT: ret void
+    unsafe { intrinsics::simd_mul(x, x) }
+}
+
+// CHECK-LABEL: square_packed
+// CHECK-SAME: ptr{{[a-z_ ]*}} sret([[RET_TYPE:[^)]+]]) [[RET_ALIGN:align 4]]{{[^%]*}} [[RET_VREG:%[_0-9]*]]
+// CHECK-SAME: ptr{{[a-z_ ]*}} align 4
+#[no_mangle]
+pub fn square_packed(x: PackedSimd<f32, 3>) -> PackedSimd<f32, 3> {
+    // CHECK-NEXT: start
+    // CHECK-NEXT: load <3 x float>
+    // noopt-NEXT: load <3 x float>
+    // CHECK-NEXT: [[VREG:%[a-z0-9_]+]] = fmul <3 x float>
+    // CHECK-NEXT: store <3 x float> [[VREG]], ptr [[RET_VREG]], [[RET_ALIGN]]
+    // CHECK-NEXT: ret void
+    unsafe { intrinsics::simd_mul(x, x) }
+}
diff --git a/tests/codegen-llvm/simd/simd-wide-sum.rs b/tests/codegen-llvm/simd/simd-wide-sum.rs
new file mode 100644
index 00000000000..95117b2c748
--- /dev/null
+++ b/tests/codegen-llvm/simd/simd-wide-sum.rs
@@ -0,0 +1,59 @@
+//@ revisions: llvm mir-opt3
+//@ compile-flags: -C opt-level=3 -Z merge-functions=disabled
+//@ edition: 2021
+//@ only-x86_64
+//@ [mir-opt3]compile-flags: -Zmir-opt-level=3
+//@ [mir-opt3]build-pass
+
+// mir-opt3 is a regression test for https://github.com/rust-lang/rust/issues/98016
+
+#![crate_type = "lib"]
+#![feature(portable_simd)]
+
+use std::simd::prelude::*;
+const N: usize = 16;
+
+#[no_mangle]
+// CHECK-LABEL: @wider_reduce_simd
+pub fn wider_reduce_simd(x: Simd<u8, N>) -> u16 {
+    // CHECK: zext <16 x i8>
+    // CHECK-SAME: to <16 x i16>
+    // CHECK: call i16 @llvm.vector.reduce.add.v16i16(<16 x i16>
+    let x: Simd<u16, N> = x.cast();
+    x.reduce_sum()
+}
+
+#[no_mangle]
+// CHECK-LABEL: @wider_reduce_loop
+pub fn wider_reduce_loop(x: Simd<u8, N>) -> u16 {
+    // CHECK: zext <16 x i8>
+    // CHECK-SAME: to <16 x i16>
+    // CHECK: call i16 @llvm.vector.reduce.add.v16i16(<16 x i16>
+    let mut sum = 0_u16;
+    for i in 0..N {
+        sum += u16::from(x[i]);
+    }
+    sum
+}
+
+#[no_mangle]
+// CHECK-LABEL: @wider_reduce_iter
+pub fn wider_reduce_iter(x: Simd<u8, N>) -> u16 {
+    // CHECK: zext <16 x i8>
+    // CHECK-SAME: to <16 x i16>
+    // CHECK: call i16 @llvm.vector.reduce.add.v16i16(<16 x i16>
+    x.as_array().iter().copied().map(u16::from).sum()
+}
+
+// This iterator one is the most interesting, as it's the one
+// which used to not auto-vectorize due to a suboptimality in the
+// `<array::IntoIter as Iterator>::fold` implementation.
+
+#[no_mangle]
+// CHECK-LABEL: @wider_reduce_into_iter
+pub fn wider_reduce_into_iter(x: Simd<u8, N>) -> u16 {
+    // CHECK: zext <16 x i8>
+    // CHECK-SAME: to <16 x i16>
+    // CHECK: call i16 @llvm.vector.reduce.add.v16i16(<16 x i16>
+    x.to_array().into_iter().map(u16::from).sum()
+}
diff --git a/tests/codegen-llvm/simd/simd_arith_offset.rs b/tests/codegen-llvm/simd/simd_arith_offset.rs
new file mode 100644
index 00000000000..210b4e9bb50
--- /dev/null
+++ b/tests/codegen-llvm/simd/simd_arith_offset.rs
@@ -0,0 +1,22 @@
+//@ compile-flags: -C no-prepopulate-passes
+//@ only-64bit (because the LLVM type of i64 for usize shows up)
+//
+
+#![crate_type = "lib"]
+#![feature(repr_simd, core_intrinsics)]
+
+#[path = "../../auxiliary/minisimd.rs"]
+mod minisimd;
+use std::intrinsics::simd::simd_arith_offset;
+
+use minisimd::*;
+
+/// A vector of *const T.
+pub type SimdConstPtr<T, const LANES: usize> = Simd<*const T, LANES>;
+
+// CHECK-LABEL: smoke
+#[no_mangle]
+pub fn smoke(ptrs: SimdConstPtr<u8, 8>, offsets: Simd<usize, 8>) -> SimdConstPtr<u8, 8> {
+    // CHECK: getelementptr i8, <8 x ptr> %0, <8 x i64> %1
+    unsafe { simd_arith_offset(ptrs, offsets) }
+}
diff --git a/tests/codegen-llvm/simd/swap-simd-types.rs b/tests/codegen-llvm/simd/swap-simd-types.rs
new file mode 100644
index 00000000000..c063cc683a6
--- /dev/null
+++ b/tests/codegen-llvm/simd/swap-simd-types.rs
@@ -0,0 +1,40 @@
+//@ compile-flags: -Copt-level=3 -C target-feature=+avx
+//@ only-x86_64
+
+#![crate_type = "lib"]
+
+use std::mem::swap;
+
+// SIMD types are highly-aligned already, so make sure the swap code leaves their
+// types alone and doesn't pessimize them (such as by swapping them as `usize`s).
+extern crate core;
+use core::arch::x86_64::__m256;
+
+// CHECK-LABEL: @swap_single_m256
+#[no_mangle]
+pub fn swap_single_m256(x: &mut __m256, y: &mut __m256) {
+    // CHECK-NOT: alloca
+    // CHECK: load <8 x float>{{.+}}align 32
+    // CHECK: store <8 x float>{{.+}}align 32
+    swap(x, y)
+}
+
+// CHECK-LABEL: @swap_m256_slice
+#[no_mangle]
+pub fn swap_m256_slice(x: &mut [__m256], y: &mut [__m256]) {
+    // CHECK-NOT: alloca
+    // CHECK-COUNT-2: load <4 x i64>{{.+}}align 32
+    // CHECK-COUNT-2: store <4 x i64>{{.+}}align 32
+    if x.len() == y.len() {
+        x.swap_with_slice(y);
+    }
+}
+
+// CHECK-LABEL: @swap_bytes32
+#[no_mangle]
+pub fn swap_bytes32(x: &mut [u8; 32], y: &mut [u8; 32]) {
+    // CHECK-NOT: alloca
+    // CHECK-COUNT-2: load <4 x i64>{{.+}}align 1
+    // CHECK-COUNT-2: store <4 x i64>{{.+}}align 1
+    swap(x, y)
+}
diff --git a/tests/codegen-llvm/simd/unpadded-simd.rs b/tests/codegen-llvm/simd/unpadded-simd.rs
new file mode 100644
index 00000000000..ef067a15702
--- /dev/null
+++ b/tests/codegen-llvm/simd/unpadded-simd.rs
@@ -0,0 +1,19 @@
+// Make sure that no 0-sized padding is inserted in structs and that
+// structs are represented as expected by Neon intrinsics in LLVM.
+// See #87254.
+
+#![crate_type = "lib"]
+#![feature(repr_simd, abi_unadjusted)]
+
+#[derive(Copy, Clone)]
+#[repr(simd)]
+pub struct int16x4_t(pub [i16; 4]);
+
+#[derive(Copy, Clone)]
+pub struct int16x4x2_t(pub int16x4_t, pub int16x4_t);
+
+// CHECK: %int16x4x2_t = type { <4 x i16>, <4 x i16> }
+#[no_mangle]
+extern "unadjusted" fn takes_int16x4x2_t(t: int16x4x2_t) -> int16x4x2_t {
+    t
+}
diff --git a/tests/codegen-llvm/skip-mono-inside-if-false.rs b/tests/codegen-llvm/skip-mono-inside-if-false.rs
new file mode 100644
index 00000000000..8b95de99dd3
--- /dev/null
+++ b/tests/codegen-llvm/skip-mono-inside-if-false.rs
@@ -0,0 +1,41 @@
+//@ compile-flags: -Cno-prepopulate-passes -Copt-level=0
+
+#![crate_type = "lib"]
+
+#[no_mangle]
+pub fn demo_for_i32() {
+    generic_impl::<i32>();
+}
+
+// Two important things here:
+// - We replace the "then" block with `unreachable` to avoid linking problems
+// - We neither declare nor define the `big_impl` that said block "calls".
+
+// CHECK-LABEL: ; skip_mono_inside_if_false::generic_impl
+// CHECK: start:
+// CHECK-NEXT: br label %[[ELSE_BRANCH:bb[0-9]+]]
+// CHECK: [[ELSE_BRANCH]]:
+// CHECK-NEXT: call skip_mono_inside_if_false::small_impl
+// CHECK: bb{{[0-9]+}}:
+// CHECK-NEXT: ret void
+// CHECK: bb{{[0-9+]}}:
+// CHECK-NEXT: unreachable
+
+fn generic_impl<T>() {
+    trait MagicTrait {
+        const IS_BIG: bool;
+    }
+    impl<T> MagicTrait for T {
+        const IS_BIG: bool = std::mem::size_of::<T>() > 10;
+    }
+    if T::IS_BIG {
+        big_impl::<T>();
+    } else {
+        small_impl::<T>();
+    }
+}
+
+#[inline(never)]
+fn small_impl<T>() {}
+#[inline(never)]
+fn big_impl<T>() {}
diff --git a/tests/codegen-llvm/slice-as_chunks.rs b/tests/codegen-llvm/slice-as_chunks.rs
new file mode 100644
index 00000000000..337eb8981f6
--- /dev/null
+++ b/tests/codegen-llvm/slice-as_chunks.rs
@@ -0,0 +1,30 @@
+//@ compile-flags: -Copt-level=3
+//@ only-64bit (because the LLVM type of i64 for usize shows up)
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @chunks4
+#[no_mangle]
+pub fn chunks4(x: &[u8]) -> &[[u8; 4]] {
+    // CHECK-NEXT: start:
+    // CHECK-NEXT: lshr i64 %x.1, 2
+    // CHECK-NOT: shl
+    // CHECK-NOT: mul
+    // CHECK-NOT: udiv
+    // CHECK-NOT: urem
+    // CHECK: ret
+    x.as_chunks().0
+}
+
+// CHECK-LABEL: @chunks4_with_remainder
+#[no_mangle]
+pub fn chunks4_with_remainder(x: &[u8]) -> (&[[u8; 4]], &[u8]) {
+    // CHECK-DAG: and i64 %x.1, -4
+    // CHECK-DAG: and i64 %x.1, 3
+    // CHECK-DAG: lshr
+    // CHECK-NOT: mul
+    // CHECK-NOT: udiv
+    // CHECK-NOT: urem
+    // CHECK: ret
+    x.as_chunks()
+}
diff --git a/tests/codegen-llvm/slice-indexing.rs b/tests/codegen-llvm/slice-indexing.rs
new file mode 100644
index 00000000000..d957ccfb5ef
--- /dev/null
+++ b/tests/codegen-llvm/slice-indexing.rs
@@ -0,0 +1,99 @@
+//@ compile-flags: -Copt-level=3
+//@ only-64bit (because the LLVM type of i64 for usize shows up)
+
+#![crate_type = "lib"]
+
+use std::ops::Range;
+
+// CHECK-LABEL: @index_by_range(
+#[no_mangle]
+pub fn index_by_range(x: &[u16], r: Range<usize>) -> &[u16] {
+    // CHECK: sub nuw i64
+    &x[r]
+}
+
+// CHECK-LABEL: @get_unchecked_by_range(
+#[no_mangle]
+pub unsafe fn get_unchecked_by_range(x: &[u16], r: Range<usize>) -> &[u16] {
+    // CHECK: sub nuw i64
+    x.get_unchecked(r)
+}
+
+// CHECK-LABEL: @index_mut_by_range(
+#[no_mangle]
+pub fn index_mut_by_range(x: &mut [i32], r: Range<usize>) -> &mut [i32] {
+    // CHECK: sub nuw i64
+    &mut x[r]
+}
+
+// CHECK-LABEL: @get_unchecked_mut_by_range(
+#[no_mangle]
+pub unsafe fn get_unchecked_mut_by_range(x: &mut [i32], r: Range<usize>) -> &mut [i32] {
+    // CHECK: sub nuw i64
+    x.get_unchecked_mut(r)
+}
+
+// CHECK-LABEL: @str_index_by_range(
+#[no_mangle]
+pub fn str_index_by_range(x: &str, r: Range<usize>) -> &str {
+    // CHECK: sub nuw i64
+    &x[r]
+}
+
+// CHECK-LABEL: @str_get_unchecked_by_range(
+#[no_mangle]
+pub unsafe fn str_get_unchecked_by_range(x: &str, r: Range<usize>) -> &str {
+    // CHECK: sub nuw i64
+    x.get_unchecked(r)
+}
+
+// CHECK-LABEL: @str_index_mut_by_range(
+#[no_mangle]
+pub fn str_index_mut_by_range(x: &mut str, r: Range<usize>) -> &mut str {
+    // CHECK: sub nuw i64
+    &mut x[r]
+}
+
+// CHECK-LABEL: @str_get_unchecked_mut_by_range(
+#[no_mangle]
+pub unsafe fn str_get_unchecked_mut_by_range(x: &mut str, r: Range<usize>) -> &mut str {
+    // CHECK: sub nuw i64
+    x.get_unchecked_mut(r)
+}
+
+// CHECK-LABEL: @slice_repeated_indexing(
+#[no_mangle]
+pub fn slice_repeated_indexing(dst: &mut [u8], offset: usize) {
+    let mut i = offset;
+    // CHECK: panic_bounds_check
+    dst[i] = 1;
+    i += 1;
+    // CHECK: panic_bounds_check
+    dst[i] = 2;
+    i += 1;
+    // CHECK: panic_bounds_check
+    dst[i] = 3;
+    i += 1;
+    // CHECK: panic_bounds_check
+    dst[i] = 4;
+}
+
+// CHECK-LABEL: @slice_repeated_indexing_coalesced(
+#[no_mangle]
+pub fn slice_repeated_indexing_coalesced(dst: &mut [u8], offset: usize) {
+    let mut i = offset;
+    if i.checked_add(4).unwrap() <= dst.len() {
+        // CHECK-NOT: panic_bounds_check
+        dst[i] = 1;
+        i += 1;
+        // CHECK-NOT: panic_bounds_check
+        dst[i] = 2;
+        i += 1;
+        // CHECK-NOT: panic_bounds_check
+        dst[i] = 3;
+        i += 1;
+        // CHECK-NOT: panic_bounds_check
+        dst[i] = 4;
+    }
+    // CHECK: ret
+}
diff --git a/tests/codegen-llvm/slice-init.rs b/tests/codegen-llvm/slice-init.rs
new file mode 100644
index 00000000000..950e0b0c10d
--- /dev/null
+++ b/tests/codegen-llvm/slice-init.rs
@@ -0,0 +1,108 @@
+//@ compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @zero_sized_elem
+#[no_mangle]
+pub fn zero_sized_elem() {
+    // CHECK-NOT: br label %repeat_loop_header{{.*}}
+    // CHECK-NOT: call void @llvm.memset.p0
+    let x = [(); 4];
+    opaque(&x);
+}
+
+// CHECK-LABEL: @zero_len_array
+#[no_mangle]
+pub fn zero_len_array() {
+    // CHECK-NOT: br label %repeat_loop_header{{.*}}
+    // CHECK-NOT: call void @llvm.memset.p0
+    let x = [4; 0];
+    opaque(&x);
+}
+
+// CHECK-LABEL: @byte_array
+#[no_mangle]
+pub fn byte_array() {
+    // CHECK: call void @llvm.memset.{{.+}}(ptr {{.*}}, i8 7, i{{[0-9]+}} 4
+    // CHECK-NOT: br label %repeat_loop_header{{.*}}
+    let x = [7u8; 4];
+    opaque(&x);
+}
+
+#[allow(dead_code)]
+#[derive(Copy, Clone)]
+enum Init {
+    Loop,
+    Memset,
+}
+
+// CHECK-LABEL: @byte_enum_array
+#[no_mangle]
+pub fn byte_enum_array() {
+    // CHECK: call void @llvm.memset.{{.+}}(ptr {{.*}}, i8 {{.*}}, i{{[0-9]+}} 4
+    // CHECK-NOT: br label %repeat_loop_header{{.*}}
+    let x = [Init::Memset; 4];
+    opaque(&x);
+}
+
+// CHECK-LABEL: @zeroed_integer_array
+#[no_mangle]
+pub fn zeroed_integer_array() {
+    // CHECK: call void @llvm.memset.{{.+}}(ptr {{.*}}, i8 0, i{{[0-9]+}} 16
+    // CHECK-NOT: br label %repeat_loop_header{{.*}}
+    let x = [0u32; 4];
+    opaque(&x);
+}
+
+// CHECK-LABEL: @nonzero_integer_array
+#[no_mangle]
+pub fn nonzero_integer_array() {
+    // CHECK: br label %repeat_loop_header{{.*}}
+    // CHECK-NOT: call void @llvm.memset.p0
+    let x = [0x1a_2b_3c_4d_u32; 4];
+    opaque(&x);
+}
+
+const N: usize = 100;
+
+// CHECK-LABEL: @u16_init_one_bytes
+#[no_mangle]
+pub fn u16_init_one_bytes() -> [u16; N] {
+    // CHECK-NOT: select
+    // CHECK-NOT: br
+    // CHECK-NOT: switch
+    // CHECK-NOT: icmp
+    // CHECK: call void @llvm.memset.p0
+    [const { u16::from_be_bytes([1, 1]) }; N]
+}
+
+// FIXME: undef bytes can just be initialized with the same value as the
+// defined bytes, if the defines bytes are all the same.
+// CHECK-LABEL: @option_none_init
+#[no_mangle]
+pub fn option_none_init() -> [Option<u8>; N] {
+    // CHECK-NOT: select
+    // CHECK: br label %repeat_loop_header{{.*}}
+    // CHECK-NOT: switch
+    // CHECK: icmp
+    // CHECK-NOT: call void @llvm.memset.p0
+    [None; N]
+}
+
+use std::mem::MaybeUninit;
+
+// FIXME: This could be optimized into a memset.
+// Regression test for <https://github.com/rust-lang/rust/issues/137892>.
+#[no_mangle]
+pub fn half_uninit() -> [(u128, MaybeUninit<u128>); N] {
+    // CHECK-NOT: select
+    // CHECK: br label %repeat_loop_header{{.*}}
+    // CHECK-NOT: switch
+    // CHECK: icmp
+    // CHECK-NOT: call void @llvm.memset.p0
+    [const { (0, MaybeUninit::uninit()) }; N]
+}
+
+// Use an opaque function to prevent rustc from removing useless drops.
+#[inline(never)]
+pub fn opaque(_: impl Sized) {}
diff --git a/tests/codegen-llvm/slice-is-ascii.rs b/tests/codegen-llvm/slice-is-ascii.rs
new file mode 100644
index 00000000000..67537c871a0
--- /dev/null
+++ b/tests/codegen-llvm/slice-is-ascii.rs
@@ -0,0 +1,16 @@
+//@ only-x86_64
+//@ compile-flags: -C opt-level=3 -C target-cpu=x86-64
+#![crate_type = "lib"]
+
+/// Check that the fast-path of `is_ascii` uses a `pmovmskb` instruction.
+/// Platforms lacking an equivalent instruction use other techniques for
+/// optimizing `is_ascii`.
+// CHECK-LABEL: @is_ascii_autovectorized
+#[no_mangle]
+pub fn is_ascii_autovectorized(s: &[u8]) -> bool {
+    // CHECK: load <32 x i8>
+    // CHECK-NEXT: icmp slt <32 x i8>
+    // CHECK-NEXT: bitcast <32 x i1>
+    // CHECK-NEXT: icmp eq i32
+    s.is_ascii()
+}
diff --git a/tests/codegen-llvm/slice-iter-fold.rs b/tests/codegen-llvm/slice-iter-fold.rs
new file mode 100644
index 00000000000..55ab34661c3
--- /dev/null
+++ b/tests/codegen-llvm/slice-iter-fold.rs
@@ -0,0 +1,12 @@
+//@ compile-flags: -Copt-level=3
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @slice_fold_to_last
+#[no_mangle]
+pub fn slice_fold_to_last(slice: &[i32]) -> Option<&i32> {
+    // CHECK-NOT: loop
+    // CHECK-NOT: br
+    // CHECK-NOT: call
+    // CHECK: ret
+    slice.iter().fold(None, |_, i| Some(i))
+}
diff --git a/tests/codegen-llvm/slice-iter-len-eq-zero.rs b/tests/codegen-llvm/slice-iter-len-eq-zero.rs
new file mode 100644
index 00000000000..6998d98e498
--- /dev/null
+++ b/tests/codegen-llvm/slice-iter-len-eq-zero.rs
@@ -0,0 +1,60 @@
+//@ compile-flags: -Copt-level=3
+//@ needs-deterministic-layouts (opposite scalar pair orders breaks it)
+#![crate_type = "lib"]
+
+type Demo = [u8; 3];
+
+// CHECK-LABEL: @slice_iter_len_eq_zero
+#[no_mangle]
+pub fn slice_iter_len_eq_zero(y: std::slice::Iter<'_, Demo>) -> bool {
+    // CHECK-NOT: sub
+    // CHECK: %[[RET:.+]] = icmp eq ptr {{%y.0, %y.1|%y.1, %y.0}}
+    // CHECK: ret i1 %[[RET]]
+    y.len() == 0
+}
+
+// CHECK-LABEL: @slice_iter_len_eq_zero_ref
+#[no_mangle]
+pub fn slice_iter_len_eq_zero_ref(y: &mut std::slice::Iter<'_, Demo>) -> bool {
+    // CHECK-NOT: sub
+    // CHECK: %[[A:.+]] = load ptr
+    // CHECK-SAME: !nonnull
+    // CHECK: %[[B:.+]] = load ptr
+    // CHECK-SAME: !nonnull
+    // CHECK: %[[RET:.+]] = icmp eq ptr %[[A]], %[[B]]
+    // CHECK: ret i1 %[[RET]]
+    y.len() == 0
+}
+
+struct MyZST;
+
+// CHECK-LABEL: @slice_zst_iter_len_eq_zero
+#[no_mangle]
+pub fn slice_zst_iter_len_eq_zero(y: std::slice::Iter<'_, MyZST>) -> bool {
+    // CHECK: %[[RET:.+]] = icmp eq ptr %y.1, null
+    // CHECK: ret i1 %[[RET]]
+    y.len() == 0
+}
+
+// CHECK-LABEL: @slice_zst_iter_len_eq_zero_ref
+#[no_mangle]
+pub fn slice_zst_iter_len_eq_zero_ref(y: &mut std::slice::Iter<'_, MyZST>) -> bool {
+    // CHECK: %[[LEN:.+]] = load ptr
+    // CHECK-NOT: !nonnull
+    // CHECK: %[[RET:.+]] = icmp eq ptr %[[LEN]], null
+    // CHECK: ret i1 %[[RET]]
+    y.len() == 0
+}
+
+// CHECK-LABEL: @array_into_iter_len_eq_zero
+#[no_mangle]
+pub fn array_into_iter_len_eq_zero(y: std::array::IntoIter<Demo, 123>) -> bool {
+    // This should be able to just check that the indexes are equal, and not
+    // need any subtractions or comparisons to handle `start > end`.
+
+    // CHECK-NOT: icmp
+    // CHECK-NOT: sub
+    // CHECK: %_0 = icmp eq {{i16|i32|i64}}
+    // CHECK: ret i1 %_0
+    y.len() == 0
+}
diff --git a/tests/codegen-llvm/slice-iter-nonnull.rs b/tests/codegen-llvm/slice-iter-nonnull.rs
new file mode 100644
index 00000000000..87907e7ad0a
--- /dev/null
+++ b/tests/codegen-llvm/slice-iter-nonnull.rs
@@ -0,0 +1,115 @@
+//@ compile-flags: -Copt-level=3
+//@ needs-deterministic-layouts
+#![crate_type = "lib"]
+#![feature(exact_size_is_empty)]
+
+// The slice iterator used to `assume` that the `start` pointer was non-null.
+// That ought to be unneeded, though, since the type is `NonNull`, so this test
+// confirms that the appropriate metadata is included to denote that.
+
+// It also used to `assume` the `end` pointer was non-null, but that's no longer
+// needed as the code changed to read it as a `NonNull`, and thus gets the
+// appropriate `!nonnull` annotations naturally.
+
+// CHECK-LABEL: @slice_iter_next(
+#[no_mangle]
+pub fn slice_iter_next<'a>(it: &mut std::slice::Iter<'a, u32>) -> Option<&'a u32> {
+    // CHECK: %[[START:.+]] = load ptr, ptr %it,
+    // CHECK-SAME: !nonnull
+    // CHECK-SAME: !noundef
+    // CHECK: %[[ENDP:.+]] = getelementptr inbounds{{( nuw)?}} i8, ptr %it, {{i32 4|i64 8}}
+    // CHECK: %[[END:.+]] = load ptr, ptr %[[ENDP]]
+    // CHECK-SAME: !nonnull
+    // CHECK-SAME: !noundef
+    // CHECK: icmp eq ptr %[[START]], %[[END]]
+
+    // CHECK: store ptr{{.+}}, ptr %it,
+
+    it.next()
+}
+
+// CHECK-LABEL: @slice_iter_next_back(
+#[no_mangle]
+pub fn slice_iter_next_back<'a>(it: &mut std::slice::Iter<'a, u32>) -> Option<&'a u32> {
+    // CHECK: %[[ENDP:.+]] = getelementptr inbounds{{( nuw)?}} i8, ptr %it, {{i32 4|i64 8}}
+    // CHECK: %[[END:.+]] = load ptr, ptr %[[ENDP]]
+    // CHECK-SAME: !nonnull
+    // CHECK-SAME: !noundef
+    // CHECK: %[[START:.+]] = load ptr, ptr %it,
+    // CHECK-SAME: !nonnull
+    // CHECK-SAME: !noundef
+    // CHECK: icmp eq ptr %[[START]], %[[END]]
+
+    // CHECK: store ptr{{.+}}, ptr %[[ENDP]],
+
+    it.next_back()
+}
+
+// The slice iterator `new` methods used to `assume` that the pointer is non-null,
+// but passing slices already requires that, to the extent that LLVM actually
+// removed the `call @llvm.assume` anyway.  These tests just demonstrate that the
+// attribute is there, and confirms adding the assume back doesn't do anything.
+
+// CHECK-LABEL: @slice_iter_new
+// CHECK-SAME: (ptr noalias noundef nonnull {{.+}} %slice.0, {{.+}} noundef %slice.1)
+#[no_mangle]
+pub fn slice_iter_new(slice: &[u32]) -> std::slice::Iter<'_, u32> {
+    // CHECK-NOT: slice
+    // CHECK: %[[END:.+]] = getelementptr inbounds{{( nuw)?}} i32{{.+}} %slice.0{{.+}} %slice.1
+    // CHECK-NOT: slice
+    // CHECK: insertvalue {{.+}} ptr %slice.0, 0
+    // CHECK-NOT: slice
+    // CHECK: insertvalue {{.+}} ptr %[[END]], 1
+    // CHECK-NOT: slice
+    // CHECK: }
+    slice.iter()
+}
+
+// CHECK-LABEL: @slice_iter_mut_new
+// CHECK-SAME: (ptr noalias noundef nonnull {{.+}} %slice.0, {{.+}} noundef %slice.1)
+#[no_mangle]
+pub fn slice_iter_mut_new(slice: &mut [u32]) -> std::slice::IterMut<'_, u32> {
+    // CHECK-NOT: slice
+    // CHECK: %[[END:.+]] = getelementptr inbounds{{( nuw)?}} i32{{.+}} %slice.0{{.+}} %slice.1
+    // CHECK-NOT: slice
+    // CHECK: insertvalue {{.+}} ptr %slice.0, 0
+    // CHECK-NOT: slice
+    // CHECK: insertvalue {{.+}} ptr %[[END]], 1
+    // CHECK-NOT: slice
+    // CHECK: }
+    slice.iter_mut()
+}
+
+// CHECK-LABEL: @slice_iter_is_empty
+#[no_mangle]
+pub fn slice_iter_is_empty(it: &std::slice::Iter<'_, u32>) -> bool {
+    // CHECK: %[[ENDP:.+]] = getelementptr inbounds{{( nuw)?}} i8, ptr %it, {{i32 4|i64 8}}
+    // CHECK: %[[END:.+]] = load ptr, ptr %[[ENDP]]
+    // CHECK-SAME: !nonnull
+    // CHECK-SAME: !noundef
+    // CHECK: %[[START:.+]] = load ptr, ptr %it,
+    // CHECK-SAME: !nonnull
+    // CHECK-SAME: !noundef
+
+    // CHECK: %[[RET:.+]] = icmp eq ptr %[[START]], %[[END]]
+    // CHECK: ret i1 %[[RET]]
+    it.is_empty()
+}
+
+// CHECK-LABEL: @slice_iter_len
+#[no_mangle]
+pub fn slice_iter_len(it: &std::slice::Iter<'_, u32>) -> usize {
+    // CHECK: %[[ENDP:.+]] = getelementptr inbounds{{( nuw)?}} i8, ptr %it, {{i32 4|i64 8}}
+    // CHECK: %[[END:.+]] = load ptr, ptr %[[ENDP]]
+    // CHECK-SAME: !nonnull
+    // CHECK-SAME: !noundef
+    // CHECK: %[[START:.+]] = load ptr, ptr %it,
+    // CHECK-SAME: !nonnull
+    // CHECK-SAME: !noundef
+
+    // CHECK: ptrtoint
+    // CHECK: ptrtoint
+    // CHECK: sub nuw
+    // CHECK: lshr exact
+    it.len()
+}
diff --git a/tests/codegen-llvm/slice-last-elements-optimization.rs b/tests/codegen-llvm/slice-last-elements-optimization.rs
new file mode 100644
index 00000000000..b90f91d7b17
--- /dev/null
+++ b/tests/codegen-llvm/slice-last-elements-optimization.rs
@@ -0,0 +1,37 @@
+//@ compile-flags: -Copt-level=3
+//@ only-x86_64
+//@ min-llvm-version: 20
+#![crate_type = "lib"]
+
+// This test verifies that LLVM 20 properly optimizes the bounds check
+// when accessing the last few elements of a slice with proper conditions.
+// Previously, this would generate an unreachable branch to
+// slice_start_index_len_fail even when the bounds check was provably safe.
+
+// CHECK-LABEL: @last_four_initial(
+#[no_mangle]
+pub fn last_four_initial(s: &[u8]) -> &[u8] {
+    // Previously this would generate a branch to slice_start_index_len_fail
+    // that is unreachable. The LLVM 20 fix should eliminate this branch.
+    // CHECK-NOT: slice_start_index_len_fail
+    // CHECK-NOT: unreachable
+    let start = if s.len() <= 4 { 0 } else { s.len() - 4 };
+    &s[start..]
+}
+
+// CHECK-LABEL: @last_four_optimized(
+#[no_mangle]
+pub fn last_four_optimized(s: &[u8]) -> &[u8] {
+    // This version was already correctly optimized before the fix in LLVM 20.
+    // CHECK-NOT: slice_start_index_len_fail
+    // CHECK-NOT: unreachable
+    if s.len() <= 4 { &s[0..] } else { &s[s.len() - 4..] }
+}
+
+// Just to verify we're correctly checking for the right thing
+// CHECK-LABEL: @test_bounds_check_happens(
+#[no_mangle]
+pub fn test_bounds_check_happens(s: &[u8], i: usize) -> &[u8] {
+    // CHECK: slice_start_index_len_fail
+    &s[i..]
+}
diff --git a/tests/codegen-llvm/slice-pointer-nonnull-unwrap.rs b/tests/codegen-llvm/slice-pointer-nonnull-unwrap.rs
new file mode 100644
index 00000000000..35e4bf2c661
--- /dev/null
+++ b/tests/codegen-llvm/slice-pointer-nonnull-unwrap.rs
@@ -0,0 +1,18 @@
+//@ compile-flags: -Copt-level=3
+#![crate_type = "lib"]
+
+use std::ptr::NonNull;
+
+// CHECK-LABEL: @slice_ptr_len_1
+// CHECK-NEXT: {{.*}}:
+// CHECK-NEXT: ret {{i(32|64)}} %ptr.1
+#[no_mangle]
+pub fn slice_ptr_len_1(ptr: *const [u8]) -> usize {
+    let ptr = ptr.cast_mut();
+    if let Some(ptr) = NonNull::new(ptr) {
+        ptr.len()
+    } else {
+        // We know ptr is null, so we know ptr.wrapping_byte_add(1) is not null.
+        NonNull::new(ptr.wrapping_byte_add(1)).unwrap().len()
+    }
+}
diff --git a/tests/codegen-llvm/slice-position-bounds-check.rs b/tests/codegen-llvm/slice-position-bounds-check.rs
new file mode 100644
index 00000000000..0d1d1d869ae
--- /dev/null
+++ b/tests/codegen-llvm/slice-position-bounds-check.rs
@@ -0,0 +1,25 @@
+//@ compile-flags: -Copt-level=3 -C panic=abort
+#![crate_type = "lib"]
+
+fn search<T: Ord + Eq>(arr: &mut [T], a: &T) -> Result<usize, ()> {
+    match arr.iter().position(|x| x == a) {
+        Some(p) => Ok(p),
+        None => Err(()),
+    }
+}
+
+// CHECK-LABEL: @position_no_bounds_check
+#[no_mangle]
+pub fn position_no_bounds_check(y: &mut [u32], x: &u32, z: &u32) -> bool {
+    // This contains "call assume" so we cannot just rule out all calls
+    // CHECK-NOT: panic_bounds_check
+    if let Ok(p) = search(y, x) { y[p] == *z } else { false }
+}
+
+// just to make sure that panicking really emits "panic_bounds_check" somewhere in the IR
+// CHECK-LABEL: @test_check
+#[no_mangle]
+pub fn test_check(y: &[i32]) -> i32 {
+    // CHECK: panic_bounds_check
+    y[12]
+}
diff --git a/tests/codegen-llvm/slice-ref-equality.rs b/tests/codegen-llvm/slice-ref-equality.rs
new file mode 100644
index 00000000000..2940378da3c
--- /dev/null
+++ b/tests/codegen-llvm/slice-ref-equality.rs
@@ -0,0 +1,90 @@
+//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled
+#![crate_type = "lib"]
+
+use std::num::NonZero;
+
+// #71602 reported a simple array comparison just generating a loop.
+// This was originally fixed by ensuring it generates a single bcmp,
+// but we now generate it as a load+icmp instead. `is_zero_slice` was
+// tweaked to still test the case of comparison against a slice,
+// and `is_zero_array` tests the new array-specific behaviour.
+// The optimization was then extended to short slice-to-array comparisons,
+// so the first test here now has a long slice to still get the bcmp.
+
+// CHECK-LABEL: @is_zero_slice_long
+#[no_mangle]
+pub fn is_zero_slice_long(data: &[u8; 456]) -> bool {
+    // CHECK: %[[BCMP:.+]] = tail call i32 @{{bcmp|memcmp}}({{.+}})
+    // CHECK-NEXT: %[[EQ:.+]] = icmp eq i32 %[[BCMP]], 0
+    // CHECK-NEXT: ret i1 %[[EQ]]
+    &data[..] == [0; 456]
+}
+
+// CHECK-LABEL: @is_zero_slice_short
+#[no_mangle]
+pub fn is_zero_slice_short(data: &[u8; 4]) -> bool {
+    // CHECK: %[[LOAD:.+]] = load i32, ptr %{{.+}}, align 1
+    // CHECK-NEXT: %[[EQ:.+]] = icmp eq i32 %[[LOAD]], 0
+    // CHECK-NEXT: ret i1 %[[EQ]]
+    &data[..] == [0; 4]
+}
+
+// CHECK-LABEL: @is_zero_array
+#[no_mangle]
+pub fn is_zero_array(data: &[u8; 4]) -> bool {
+    // CHECK: %[[LOAD:.+]] = load i32, ptr %{{.+}}, align 1
+    // CHECK-NEXT: %[[EQ:.+]] = icmp eq i32 %[[LOAD]], 0
+    // CHECK-NEXT: ret i1 %[[EQ]]
+    *data == [0; 4]
+}
+
+// The following test the extra specializations to make sure that slice
+// equality for non-byte types also just emit a `bcmp`, not a loop.
+
+// CHECK-LABEL: @eq_slice_of_nested_u8(
+// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %x.1
+// CHECK-SAME: [[USIZE]] noundef %y.1
+#[no_mangle]
+fn eq_slice_of_nested_u8(x: &[[u8; 3]], y: &[[u8; 3]]) -> bool {
+    // CHECK: icmp eq [[USIZE]] %x.1, %y.1
+    // CHECK: %[[BYTES:.+]] = mul nuw nsw [[USIZE]] {{%x.1|%y.1}}, 3
+    // CHECK: tail call{{( noundef)?}} i32 @{{bcmp|memcmp}}(ptr
+    // CHECK-SAME: , [[USIZE]]{{( noundef)?}} %[[BYTES]])
+    x == y
+}
+
+// CHECK-LABEL: @eq_slice_of_i32(
+// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %x.1
+// CHECK-SAME: [[USIZE]] noundef %y.1
+#[no_mangle]
+fn eq_slice_of_i32(x: &[i32], y: &[i32]) -> bool {
+    // CHECK: icmp eq [[USIZE]] %x.1, %y.1
+    // CHECK: %[[BYTES:.+]] = shl nuw nsw [[USIZE]] {{%x.1|%y.1}}, 2
+    // CHECK: tail call{{( noundef)?}} i32 @{{bcmp|memcmp}}(ptr
+    // CHECK-SAME: , [[USIZE]]{{( noundef)?}} %[[BYTES]])
+    x == y
+}
+
+// CHECK-LABEL: @eq_slice_of_nonzero(
+// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %x.1
+// CHECK-SAME: [[USIZE]] noundef %y.1
+#[no_mangle]
+fn eq_slice_of_nonzero(x: &[NonZero<i32>], y: &[NonZero<i32>]) -> bool {
+    // CHECK: icmp eq [[USIZE]] %x.1, %y.1
+    // CHECK: %[[BYTES:.+]] = shl nuw nsw [[USIZE]] {{%x.1|%y.1}}, 2
+    // CHECK: tail call{{( noundef)?}} i32 @{{bcmp|memcmp}}(ptr
+    // CHECK-SAME: , [[USIZE]]{{( noundef)?}} %[[BYTES]])
+    x == y
+}
+
+// CHECK-LABEL: @eq_slice_of_option_of_nonzero(
+// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %x.1
+// CHECK-SAME: [[USIZE]] noundef %y.1
+#[no_mangle]
+fn eq_slice_of_option_of_nonzero(x: &[Option<NonZero<i16>>], y: &[Option<NonZero<i16>>]) -> bool {
+    // CHECK: icmp eq [[USIZE]] %x.1, %y.1
+    // CHECK: %[[BYTES:.+]] = shl nuw nsw [[USIZE]] {{%x.1|%y.1}}, 1
+    // CHECK: tail call{{( noundef)?}} i32 @{{bcmp|memcmp}}(ptr
+    // CHECK-SAME: , [[USIZE]]{{( noundef)?}} %[[BYTES]])
+    x == y
+}
diff --git a/tests/codegen-llvm/slice-reverse.rs b/tests/codegen-llvm/slice-reverse.rs
new file mode 100644
index 00000000000..e58d1c1d9d8
--- /dev/null
+++ b/tests/codegen-llvm/slice-reverse.rs
@@ -0,0 +1,27 @@
+//@ compile-flags: -Copt-level=3
+//@ only-x86_64
+//@ ignore-std-debug-assertions (debug assertions prevent generating shufflevector)
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @slice_reverse_u8
+#[no_mangle]
+pub fn slice_reverse_u8(slice: &mut [u8]) {
+    // CHECK-NOT: panic_bounds_check
+    // CHECK-NOT: slice_end_index_len_fail
+    // CHECK: shufflevector <{{[0-9]+}} x i8>
+    // CHECK-NOT: panic_bounds_check
+    // CHECK-NOT: slice_end_index_len_fail
+    slice.reverse();
+}
+
+// CHECK-LABEL: @slice_reverse_i32
+#[no_mangle]
+pub fn slice_reverse_i32(slice: &mut [i32]) {
+    // CHECK-NOT: panic_bounds_check
+    // CHECK-NOT: slice_end_index_len_fail
+    // CHECK: shufflevector <{{[0-9]+}} x i32>
+    // CHECK-NOT: panic_bounds_check
+    // CHECK-NOT: slice_end_index_len_fail
+    slice.reverse();
+}
diff --git a/tests/codegen-llvm/slice-split-at.rs b/tests/codegen-llvm/slice-split-at.rs
new file mode 100644
index 00000000000..07018cf9c91
--- /dev/null
+++ b/tests/codegen-llvm/slice-split-at.rs
@@ -0,0 +1,24 @@
+//@ compile-flags: -Copt-level=3
+#![crate_type = "lib"]
+
+// Check that no panic is generated in `split_at` when calculating the index for
+// the tail chunk using `checked_sub`.
+//
+// Tests written for refactored implementations of:
+// `<[T]>::{split_last_chunk, split_last_chunk_mut, last_chunk, last_chunk_mut}`
+
+// CHECK-LABEL: @split_at_last_chunk
+#[no_mangle]
+pub fn split_at_last_chunk(s: &[u8], chunk_size: usize) -> Option<(&[u8], &[u8])> {
+    // CHECK-NOT: panic
+    let Some(index) = s.len().checked_sub(chunk_size) else { return None };
+    Some(s.split_at(index))
+}
+
+// CHECK-LABEL: @split_at_mut_last_chunk
+#[no_mangle]
+pub fn split_at_mut_last_chunk(s: &mut [u8], chunk_size: usize) -> Option<(&mut [u8], &mut [u8])> {
+    // CHECK-NOT: panic
+    let Some(index) = s.len().checked_sub(chunk_size) else { return None };
+    Some(s.split_at_mut(index))
+}
diff --git a/tests/codegen-llvm/slice-windows-no-bounds-check.rs b/tests/codegen-llvm/slice-windows-no-bounds-check.rs
new file mode 100644
index 00000000000..87e89b14f06
--- /dev/null
+++ b/tests/codegen-llvm/slice-windows-no-bounds-check.rs
@@ -0,0 +1,32 @@
+#![crate_type = "lib"]
+
+//@ compile-flags: -Copt-level=3
+
+use std::slice::Windows;
+
+// CHECK-LABEL: @naive_string_search
+#[no_mangle]
+pub fn naive_string_search(haystack: &str, needle: &str) -> Option<usize> {
+    if needle.is_empty() {
+        return Some(0);
+    }
+    // CHECK-NOT: panic
+    // CHECK-NOT: fail
+    haystack.as_bytes().windows(needle.len()).position(|sub| sub == needle.as_bytes())
+}
+
+// CHECK-LABEL: @next
+#[no_mangle]
+pub fn next<'a>(w: &mut Windows<'a, u32>) -> Option<&'a [u32]> {
+    // CHECK-NOT: panic
+    // CHECK-NOT: fail
+    w.next()
+}
+
+// CHECK-LABEL: @next_back
+#[no_mangle]
+pub fn next_back<'a>(w: &mut Windows<'a, u32>) -> Option<&'a [u32]> {
+    // CHECK-NOT: panic
+    // CHECK-NOT: fail
+    w.next_back()
+}
diff --git a/tests/codegen-llvm/slice_as_from_ptr_range.rs b/tests/codegen-llvm/slice_as_from_ptr_range.rs
new file mode 100644
index 00000000000..2073f05c07f
--- /dev/null
+++ b/tests/codegen-llvm/slice_as_from_ptr_range.rs
@@ -0,0 +1,21 @@
+//@ compile-flags: -Copt-level=3
+//@ only-64bit (because we're using [ui]size)
+
+#![crate_type = "lib"]
+#![feature(slice_from_ptr_range)]
+
+// This is intentionally using a non-power-of-two array length,
+// as that's where the optimization differences show up
+
+// CHECK-LABEL: @flatten_via_ptr_range
+#[no_mangle]
+pub fn flatten_via_ptr_range(slice_of_arrays: &[[i32; 13]]) -> &[i32] {
+    // CHECK-NOT: lshr
+    // CHECK-NOT: udiv
+    // CHECK: mul nuw nsw i64 %{{.+}}, 13
+    // CHECK-NOT: lshr
+    // CHECK-NOT: udiv
+    let r = slice_of_arrays.as_ptr_range();
+    let r = r.start.cast()..r.end.cast();
+    unsafe { core::slice::from_ptr_range(r) }
+}
diff --git a/tests/codegen-llvm/some-abis-do-extend-params-to-32-bits.rs b/tests/codegen-llvm/some-abis-do-extend-params-to-32-bits.rs
new file mode 100644
index 00000000000..6ca6697588f
--- /dev/null
+++ b/tests/codegen-llvm/some-abis-do-extend-params-to-32-bits.rs
@@ -0,0 +1,236 @@
+//@ add-core-stubs
+//@ compile-flags: -Cno-prepopulate-passes -Copt-level=0
+
+//@ revisions:x86_64 i686 aarch64-apple aarch64-windows aarch64-linux arm riscv
+
+//@[x86_64] compile-flags: --target x86_64-unknown-uefi
+//@[x86_64] needs-llvm-components: x86
+//@[i686] compile-flags: --target i686-unknown-linux-musl
+//@[i686] needs-llvm-components: x86
+//@[aarch64-windows] compile-flags: --target aarch64-pc-windows-msvc
+//@[aarch64-windows] needs-llvm-components: aarch64
+//@[aarch64-linux] compile-flags: --target aarch64-unknown-linux-gnu
+//@[aarch64-linux] needs-llvm-components: aarch64
+//@[aarch64-apple] compile-flags: --target aarch64-apple-darwin
+//@[aarch64-apple] needs-llvm-components: aarch64
+//@[arm] compile-flags: --target armv7r-none-eabi
+//@[arm] needs-llvm-components: arm
+//@[riscv] compile-flags: --target riscv64gc-unknown-none-elf
+//@[riscv] needs-llvm-components: riscv
+
+// See bottom of file for a corresponding C source file that is meant to yield
+// equivalent declarations.
+#![feature(no_core, lang_items)]
+#![crate_type = "lib"]
+#![no_std]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+// The patterns in this file are written in the style of a table to make the
+// uniformities and distinctions more apparent.
+//
+//                  ZERO/SIGN-EXTENDING TO 32 BITS            NON-EXTENDING
+//                  ==============================  =======================
+// x86_64:          void @c_arg_u8(i8 zeroext %_a)
+// i686:            void @c_arg_u8(i8 zeroext %_a)
+// aarch64-apple:   void @c_arg_u8(i8 zeroext %_a)
+// aarch64-windows:                                  void @c_arg_u8(i8 %_a)
+// aarch64-linux:                                    void @c_arg_u8(i8 %_a)
+// arm:             void @c_arg_u8(i8 zeroext %_a)
+// riscv:           void @c_arg_u8(i8 zeroext %_a)
+#[no_mangle]
+pub extern "C" fn c_arg_u8(_a: u8) {}
+
+// x86_64:          void @c_arg_u16(i16 zeroext %_a)
+// i686:            void @c_arg_u16(i16 zeroext %_a)
+// aarch64-apple:   void @c_arg_u16(i16 zeroext %_a)
+// aarch64-windows:                                 void @c_arg_u16(i16 %_a)
+// aarch64-linux:                                   void @c_arg_u16(i16 %_a)
+// arm:             void @c_arg_u16(i16 zeroext %_a)
+// riscv:           void @c_arg_u16(i16 zeroext %_a)
+#[no_mangle]
+pub extern "C" fn c_arg_u16(_a: u16) {}
+
+// x86_64:          void @c_arg_u32(i32 %_a)
+// i686:            void @c_arg_u32(i32 %_a)
+// aarch64-apple:   void @c_arg_u32(i32 %_a)
+// aarch64-windows:                                 void @c_arg_u32(i32 %_a)
+// aarch64-linux:                                   void @c_arg_u32(i32 %_a)
+// arm:             void @c_arg_u32(i32 %_a)
+// riscv:           void @c_arg_u32(i32 signext %_a)
+#[no_mangle]
+pub extern "C" fn c_arg_u32(_a: u32) {}
+
+// x86_64:          void @c_arg_u64(i64 %_a)
+// i686:            void @c_arg_u64(i64 %_a)
+// aarch64-apple:   void @c_arg_u64(i64 %_a)
+// aarch64-windows:                                 void @c_arg_u64(i64 %_a)
+// aarch64-linux:                                   void @c_arg_u64(i64 %_a)
+// arm:             void @c_arg_u64(i64 %_a)
+// riscv:           void @c_arg_u64(i64 %_a)
+#[no_mangle]
+pub extern "C" fn c_arg_u64(_a: u64) {}
+
+// x86_64:          void @c_arg_i8(i8 signext %_a)
+// i686:            void @c_arg_i8(i8 signext %_a)
+// aarch64-apple:   void @c_arg_i8(i8 signext %_a)
+// aarch64-windows:                                  void @c_arg_i8(i8 %_a)
+// aarch64-linux:                                    void @c_arg_i8(i8 %_a)
+// arm:             void @c_arg_i8(i8 signext %_a)
+// riscv:           void @c_arg_i8(i8 signext %_a)
+#[no_mangle]
+pub extern "C" fn c_arg_i8(_a: i8) {}
+
+// x86_64:          void @c_arg_i16(i16 signext %_a)
+// i686:            void @c_arg_i16(i16 signext %_a)
+// aarch64-apple:   void @c_arg_i16(i16 signext %_a)
+// aarch64-windows:                                 void @c_arg_i16(i16 %_a)
+// aarch64-linux:                                   void @c_arg_i16(i16 %_a)
+// arm:             void @c_arg_i16(i16 signext %_a)
+// riscv:           void @c_arg_i16(i16 signext %_a)
+#[no_mangle]
+pub extern "C" fn c_arg_i16(_a: i16) {}
+
+// x86_64:          void @c_arg_i32(i32 %_a)
+// i686:            void @c_arg_i32(i32 %_a)
+// aarch64-apple:   void @c_arg_i32(i32 %_a)
+// aarch64-windows:                                 void @c_arg_i32(i32 %_a)
+// aarch64-linux:                                   void @c_arg_i32(i32 %_a)
+// arm:             void @c_arg_i32(i32 %_a)
+// riscv:           void @c_arg_i32(i32 signext %_a)
+#[no_mangle]
+pub extern "C" fn c_arg_i32(_a: i32) {}
+
+// x86_64:          void @c_arg_i64(i64 %_a)
+// i686:            void @c_arg_i64(i64 %_a)
+// aarch64-apple:   void @c_arg_i64(i64 %_a)
+// aarch64-windows:                                 void @c_arg_i64(i64 %_a)
+// aarch64-linux:                                   void @c_arg_i64(i64 %_a)
+// arm:             void @c_arg_i64(i64 %_a)
+// riscv:           void @c_arg_i64(i64 %_a)
+#[no_mangle]
+pub extern "C" fn c_arg_i64(_a: i64) {}
+
+// x86_64:          zeroext i8 @c_ret_u8()
+// i686:            zeroext i8 @c_ret_u8()
+// aarch64-apple:   zeroext i8 @c_ret_u8()
+// aarch64-windows:                                 i8 @c_ret_u8()
+// aarch64-linux:                                   i8 @c_ret_u8()
+// arm:             zeroext i8 @c_ret_u8()
+// riscv:           zeroext i8 @c_ret_u8()
+#[no_mangle]
+pub extern "C" fn c_ret_u8() -> u8 {
+    0
+}
+
+// x86_64:          zeroext i16 @c_ret_u16()
+// i686:            zeroext i16 @c_ret_u16()
+// aarch64-apple:   zeroext i16 @c_ret_u16()
+// aarch64-windows:                                 i16 @c_ret_u16()
+// aarch64-linux:                                   i16 @c_ret_u16()
+// arm:             zeroext i16 @c_ret_u16()
+// riscv:           zeroext i16 @c_ret_u16()
+#[no_mangle]
+pub extern "C" fn c_ret_u16() -> u16 {
+    0
+}
+
+// x86_64:          i32 @c_ret_u32()
+// i686:            i32 @c_ret_u32()
+// aarch64-apple:   i32 @c_ret_u32()
+// aarch64-windows:                                 i32 @c_ret_u32()
+// aarch64-linux:                                   i32 @c_ret_u32()
+// arm:             i32 @c_ret_u32()
+// riscv:           signext i32 @c_ret_u32()
+#[no_mangle]
+pub extern "C" fn c_ret_u32() -> u32 {
+    0
+}
+
+// x86_64:          i64 @c_ret_u64()
+// i686:            i64 @c_ret_u64()
+// aarch64-apple:   i64 @c_ret_u64()
+// aarch64-windows:                                 i64 @c_ret_u64()
+// aarch64-linux:                                   i64 @c_ret_u64()
+// arm:             i64 @c_ret_u64()
+// riscv:           i64 @c_ret_u64()
+#[no_mangle]
+pub extern "C" fn c_ret_u64() -> u64 {
+    0
+}
+
+// x86_64:          signext i8 @c_ret_i8()
+// i686:            signext i8 @c_ret_i8()
+// aarch64-apple:   signext i8 @c_ret_i8()
+// aarch64-windows:                                 i8 @c_ret_i8()
+// aarch64-linux:                                   i8 @c_ret_i8()
+// arm:             signext i8 @c_ret_i8()
+// riscv:           signext i8 @c_ret_i8()
+#[no_mangle]
+pub extern "C" fn c_ret_i8() -> i8 {
+    0
+}
+
+// x86_64:          signext i16 @c_ret_i16()
+// i686:            signext i16 @c_ret_i16()
+// aarch64-apple:   signext i16 @c_ret_i16()
+// aarch64-windows:                                 i16 @c_ret_i16()
+// aarch64-linux:                                   i16 @c_ret_i16()
+// arm:             signext i16 @c_ret_i16()
+// riscv:           signext i16 @c_ret_i16()
+#[no_mangle]
+pub extern "C" fn c_ret_i16() -> i16 {
+    0
+}
+
+// x86_64:          i32 @c_ret_i32()
+// i686:            i32 @c_ret_i32()
+// aarch64-apple:   i32 @c_ret_i32()
+// aarch64-windows:                                 i32 @c_ret_i32()
+// aarch64-linux:                                   i32 @c_ret_i32()
+// arm:             i32 @c_ret_i32()
+// riscv:           signext i32 @c_ret_i32()
+#[no_mangle]
+pub extern "C" fn c_ret_i32() -> i32 {
+    0
+}
+
+// x86_64:          i64 @c_ret_i64()
+// i686:            i64 @c_ret_i64()
+// aarch64-apple:   i64 @c_ret_i64()
+// aarch64-windows:                                 i64 @c_ret_i64()
+// aarch64-linux:                                   i64 @c_ret_i64()
+// arm:             i64 @c_ret_i64()
+// riscv:           i64 @c_ret_i64()
+#[no_mangle]
+pub extern "C" fn c_ret_i64() -> i64 {
+    0
+}
+
+const C_SOURCE_FILE: &'static str = r##"
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+
+void c_arg_u8(uint8_t _a) { }
+void c_arg_u16(uint16_t _a) { }
+void c_arg_u32(uint32_t _a) { }
+void c_arg_u64(uint64_t _a) { }
+
+void c_arg_i8(int8_t _a) { }
+void c_arg_i16(int16_t _a) { }
+void c_arg_i32(int32_t _a) { }
+void c_arg_i64(int64_t _a) { }
+
+uint8_t  c_ret_u8()  { return 0; }
+uint16_t c_ret_u16() { return 0; }
+uint32_t c_ret_u32() { return 0; }
+uint64_t c_ret_u64() { return 0; }
+
+int8_t   c_ret_i8()  { return 0; }
+int16_t  c_ret_i16() { return 0; }
+int32_t  c_ret_i32() { return 0; }
+int64_t  c_ret_i64() { return 0; }
+"##;
diff --git a/tests/codegen-llvm/some-global-nonnull.rs b/tests/codegen-llvm/some-global-nonnull.rs
new file mode 100644
index 00000000000..bb4d12e1c76
--- /dev/null
+++ b/tests/codegen-llvm/some-global-nonnull.rs
@@ -0,0 +1,25 @@
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @test
+// CHECK-NEXT: start:
+// CHECK-NEXT: tail call void @ext_fn0()
+#[no_mangle]
+pub fn test() {
+    test_inner(Some(inner0));
+}
+
+fn test_inner(f_maybe: Option<fn()>) {
+    if let Some(f) = f_maybe {
+        f();
+    }
+}
+
+fn inner0() {
+    unsafe { ext_fn0() };
+}
+
+extern "C" {
+    fn ext_fn0();
+}
diff --git a/tests/codegen-llvm/sparc-struct-abi.rs b/tests/codegen-llvm/sparc-struct-abi.rs
new file mode 100644
index 00000000000..32d2c5bb0ef
--- /dev/null
+++ b/tests/codegen-llvm/sparc-struct-abi.rs
@@ -0,0 +1,97 @@
+// Checks that we correctly codegen extern "C" functions returning structs.
+// See issues #52638 and #86163.
+
+//@ add-core-stubs
+//@ compile-flags: -Copt-level=3 --target=sparc64-unknown-linux-gnu --crate-type=rlib
+//@ needs-llvm-components: sparc
+#![feature(no_core, lang_items)]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+#[repr(C)]
+pub struct Bool {
+    b: bool,
+}
+
+// CHECK: define{{.*}} i64 @structbool()
+// CHECK-NEXT: start:
+// CHECK-NEXT: ret i64 72057594037927936
+#[no_mangle]
+pub extern "C" fn structbool() -> Bool {
+    Bool { b: true }
+}
+
+#[repr(C)]
+pub struct BoolFloat {
+    b: bool,
+    f: f32,
+}
+
+// CHECK: define inreg { i32, float } @structboolfloat()
+// CHECK-NEXT: start:
+// CHECK-NEXT: ret { i32, float } { i32 16777216, float 0x40091EB860000000 }
+#[no_mangle]
+pub extern "C" fn structboolfloat() -> BoolFloat {
+    BoolFloat { b: true, f: 3.14 }
+}
+
+// CHECK: define void @structboolfloat_input({ i32, float } inreg %0)
+// CHECK-NEXT: start:
+#[no_mangle]
+pub extern "C" fn structboolfloat_input(a: BoolFloat) {}
+
+#[repr(C)]
+pub struct ShortDouble {
+    s: i16,
+    d: f64,
+}
+
+// CHECK: define { i64, double } @structshortdouble()
+// CHECK-NEXT: start:
+// CHECK-NEXT: ret { i64, double } { i64 34621422135410688, double 3.140000e+00 }
+#[no_mangle]
+pub extern "C" fn structshortdouble() -> ShortDouble {
+    ShortDouble { s: 123, d: 3.14 }
+}
+
+// CHECK: define void @structshortdouble_input({ i64, double } %0)
+// CHECK-NEXT: start:
+#[no_mangle]
+pub extern "C" fn structshortdouble_input(a: ShortDouble) {}
+
+#[repr(C)]
+pub struct FloatLongFloat {
+    f: f32,
+    i: i64,
+    g: f32,
+}
+
+// CHECK: define inreg { float, i32, i64, float, i32 } @structfloatlongfloat()
+// CHECK-NEXT: start:
+// CHECK-NEXT: ret { float, i32, i64, float, i32 } { float 0x3FB99999A0000000, i32 undef, i64 123, float 0x40091EB860000000, i32 undef }
+#[no_mangle]
+pub extern "C" fn structfloatlongfloat() -> FloatLongFloat {
+    FloatLongFloat { f: 0.1, i: 123, g: 3.14 }
+}
+
+#[repr(C)]
+pub struct FloatFloat {
+    f: f32,
+    g: f32,
+}
+
+#[repr(C)]
+pub struct NestedStructs {
+    a: FloatFloat,
+    b: FloatFloat,
+}
+
+// CHECK: define inreg { float, float, float, float } @structnestestructs()
+// CHECK-NEXT: start:
+// CHECK-NEXT: ret { float, float, float, float } { float 0x3FB99999A0000000, float 0x3FF19999A0000000, float 0x40019999A0000000, float 0x400A666660000000 }
+#[no_mangle]
+pub extern "C" fn structnestestructs() -> NestedStructs {
+    NestedStructs { a: FloatFloat { f: 0.1, g: 1.1 }, b: FloatFloat { f: 2.2, g: 3.3 } }
+}
diff --git a/tests/codegen-llvm/split-lto-unit.rs b/tests/codegen-llvm/split-lto-unit.rs
new file mode 100644
index 00000000000..7858a0e7b79
--- /dev/null
+++ b/tests/codegen-llvm/split-lto-unit.rs
@@ -0,0 +1,10 @@
+// Verifies that "EnableSplitLTOUnit" module flag is added.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Ctarget-feature=-crt-static -Zsplit-lto-unit
+
+#![crate_type = "lib"]
+
+pub fn foo() {}
+
+// CHECK: !{{[0-9]+}} = !{i32 4, !"EnableSplitLTOUnit", i32 1}
diff --git a/tests/codegen-llvm/src-hash-algorithm/src-hash-algorithm-md5.rs b/tests/codegen-llvm/src-hash-algorithm/src-hash-algorithm-md5.rs
new file mode 100644
index 00000000000..7aec8d545dc
--- /dev/null
+++ b/tests/codegen-llvm/src-hash-algorithm/src-hash-algorithm-md5.rs
@@ -0,0 +1,6 @@
+//@ compile-flags: -g -Z src-hash-algorithm=md5 -Copt-level=0
+
+#![crate_type = "lib"]
+
+pub fn test() {}
+// CHECK: checksumkind: CSK_MD5
diff --git a/tests/codegen-llvm/src-hash-algorithm/src-hash-algorithm-sha1.rs b/tests/codegen-llvm/src-hash-algorithm/src-hash-algorithm-sha1.rs
new file mode 100644
index 00000000000..5389c32f938
--- /dev/null
+++ b/tests/codegen-llvm/src-hash-algorithm/src-hash-algorithm-sha1.rs
@@ -0,0 +1,6 @@
+//@ compile-flags: -g -Z src-hash-algorithm=sha1 -Copt-level=0
+
+#![crate_type = "lib"]
+
+pub fn test() {}
+// CHECK: checksumkind: CSK_SHA1
diff --git a/tests/codegen-llvm/src-hash-algorithm/src-hash-algorithm-sha256.rs b/tests/codegen-llvm/src-hash-algorithm/src-hash-algorithm-sha256.rs
new file mode 100644
index 00000000000..520890c47f1
--- /dev/null
+++ b/tests/codegen-llvm/src-hash-algorithm/src-hash-algorithm-sha256.rs
@@ -0,0 +1,6 @@
+//@ compile-flags: -g -Z src-hash-algorithm=sha256 -Copt-level=0
+
+#![crate_type = "lib"]
+
+pub fn test() {}
+// CHECK: checksumkind: CSK_SHA256
diff --git a/tests/codegen-llvm/sroa-fragment-debuginfo.rs b/tests/codegen-llvm/sroa-fragment-debuginfo.rs
new file mode 100644
index 00000000000..0413cf96894
--- /dev/null
+++ b/tests/codegen-llvm/sroa-fragment-debuginfo.rs
@@ -0,0 +1,46 @@
+//@ compile-flags: -g -Zmir-opt-level=0 -Zmir-enable-passes=+ScalarReplacementOfAggregates
+//@ compile-flags: -Cno-prepopulate-passes
+//
+// Tested offsets are only correct for x86_64.
+//@ only-x86_64
+
+#![crate_type = "lib"]
+
+pub struct ExtraSlice<'input> {
+    slice: &'input [u8],
+    extra: u32,
+}
+
+#[no_mangle]
+pub fn extra(s: &[u8]) {
+    // CHECK: void @extra(
+    // CHECK: %slice.dbg.spill1 = alloca [4 x i8],
+    // CHECK: %slice.dbg.spill = alloca [16 x i8],
+    // CHECK: %s.dbg.spill = alloca [16 x i8],
+    // CHECK: dbg{{.}}declare({{(metadata )?}}ptr %s.dbg.spill, {{(metadata )?}}![[S_EXTRA:.*]], {{(metadata )?}}!DIExpression()
+    // CHECK: dbg{{.}}declare({{(metadata )?}}ptr %slice.dbg.spill, {{(metadata )?}}![[SLICE_EXTRA:.*]], {{(metadata )?}}!DIExpression(DW_OP_LLVM_fragment, 0, 128)
+    // CHECK: dbg{{.}}declare({{(metadata )?}}ptr %slice.dbg.spill1, {{(metadata )?}}![[SLICE_EXTRA]], {{(metadata )?}}!DIExpression(DW_OP_LLVM_fragment, 128, 32)
+    let slice = ExtraSlice { slice: s, extra: s.len() as u32 };
+}
+
+struct Zst;
+
+pub struct ZstSlice<'input> {
+    slice: &'input [u8],
+    extra: Zst,
+}
+
+#[no_mangle]
+pub fn zst(s: &[u8]) {
+    // The field `extra` is a ZST. The fragment for the field `slice` encompasses the whole
+    // variable, so is not a fragment. In that case, the variable must have no fragment.
+
+    // CHECK: void @zst(
+    // CHECK-NOT: dbg{{.}}declare({{(metadata )?}}ptr %slice.dbg.spill, {{(metadata )?}}!{}, {{(metadata )?}}!DIExpression(DW_OP_LLVM_fragment,
+    // CHECK: dbg{{.}}declare({{(metadata )?}}ptr %{{.*}}, {{(metadata )?}}![[SLICE_ZST:.*]], {{(metadata )?}}!DIExpression()
+    // CHECK-NOT: dbg{{.}}declare({{(metadata )?}}ptr %{{.*}}, {{(metadata )?}}![[SLICE_ZST]],
+    let slice = ZstSlice { slice: s, extra: Zst };
+}
+
+// CHECK: ![[S_EXTRA]] = !DILocalVariable(name: "s",
+// CHECK: ![[SLICE_EXTRA]] = !DILocalVariable(name: "slice",
diff --git a/tests/codegen-llvm/sse42-implies-crc32.rs b/tests/codegen-llvm/sse42-implies-crc32.rs
new file mode 100644
index 00000000000..8a9c496a3a5
--- /dev/null
+++ b/tests/codegen-llvm/sse42-implies-crc32.rs
@@ -0,0 +1,15 @@
+//@ only-x86_64
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+
+#[cfg(target_arch = "x86_64")]
+#[target_feature(enable = "sse4.2")]
+#[no_mangle]
+pub unsafe fn crc32sse(v: u8) -> u32 {
+    use std::arch::x86_64::*;
+    let out = !0u32;
+    _mm_crc32_u8(out, v)
+}
+
+// CHECK: attributes #0 {{.*"target-features"=".*\+sse4.2,\+crc32.*"}}
diff --git a/tests/codegen-llvm/stack-probes-inline.rs b/tests/codegen-llvm/stack-probes-inline.rs
new file mode 100644
index 00000000000..746272b0994
--- /dev/null
+++ b/tests/codegen-llvm/stack-probes-inline.rs
@@ -0,0 +1,33 @@
+// Check the "probe-stack" attribute for targets with `StackProbeType::Inline`,
+// or `StackProbeType::InlineOrCall` when running on newer LLVM.
+
+//@ add-core-stubs
+//@ compile-flags: -C no-prepopulate-passes
+//@ revisions: aarch64 powerpc powerpc64 powerpc64le s390x i686 x86_64
+//@[aarch64] compile-flags: --target aarch64-unknown-linux-gnu
+//@[aarch64] needs-llvm-components: aarch64
+//@[powerpc] compile-flags: --target powerpc-unknown-linux-gnu
+//@[powerpc] needs-llvm-components: powerpc
+//@[powerpc64] compile-flags: --target powerpc64-unknown-linux-gnu
+//@[powerpc64] needs-llvm-components: powerpc
+//@[powerpc64le] compile-flags: --target powerpc64le-unknown-linux-gnu
+//@[powerpc64le] needs-llvm-components: powerpc
+//@[s390x] compile-flags: --target s390x-unknown-linux-gnu
+//@[s390x] needs-llvm-components: systemz
+//@[i686] compile-flags: --target i686-unknown-linux-gnu
+//@[i686] needs-llvm-components: x86
+//@[x86_64] compile-flags: --target x86_64-unknown-linux-gnu
+//@[x86_64] needs-llvm-components: x86
+
+#![crate_type = "rlib"]
+#![feature(no_core, lang_items)]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+#[no_mangle]
+pub fn foo() {
+    // CHECK: @foo() unnamed_addr #0
+    // CHECK: attributes #0 = { {{.*}}"probe-stack"="inline-asm"{{.*}} }
+}
diff --git a/tests/codegen-llvm/stack-protector.rs b/tests/codegen-llvm/stack-protector.rs
new file mode 100644
index 00000000000..8ab25b470cd
--- /dev/null
+++ b/tests/codegen-llvm/stack-protector.rs
@@ -0,0 +1,34 @@
+//@ revisions: all strong basic none
+//@ ignore-nvptx64 stack protector not supported
+//@ [all] compile-flags: -Z stack-protector=all
+//@ [strong] compile-flags: -Z stack-protector=strong
+//@ [basic] compile-flags: -Z stack-protector=basic
+
+#![crate_type = "lib"]
+
+#[no_mangle]
+pub fn foo() {
+    // CHECK: @foo() unnamed_addr #0
+
+    // all-NOT: attributes #0 = { {{.*}}sspstrong {{.*}} }
+    // all-NOT: attributes #0 = { {{.*}}ssp {{.*}} }
+    // all: attributes #0 = { {{.*}}sspreq {{.*}} }
+    // all-NOT: attributes #0 = { {{.*}}sspstrong {{.*}} }
+    // all-NOT: attributes #0 = { {{.*}}ssp {{.*}} }
+
+    // strong-NOT: attributes #0 = { {{.*}}sspreq {{.*}} }
+    // strong-NOT: attributes #0 = { {{.*}}ssp {{.*}} }
+    // strong: attributes #0 = { {{.*}}sspstrong {{.*}} }
+    // strong-NOT: attributes #0 = { {{.*}}sspreq {{.*}} }
+    // strong-NOT: attributes #0 = { {{.*}}ssp {{.*}} }
+
+    // basic-NOT: attributes #0 = { {{.*}}sspreq {{.*}} }
+    // basic-NOT: attributes #0 = { {{.*}}sspstrong {{.*}} }
+    // basic: attributes #0 = { {{.*}}ssp {{.*}} }
+    // basic-NOT: attributes #0 = { {{.*}}sspreq {{.*}} }
+    // basic-NOT: attributes #0 = { {{.*}}sspstrong {{.*}} }
+
+    // none-NOT: attributes #0 = { {{.*}}sspreq {{.*}} }
+    // none-NOT: attributes #0 = { {{.*}}sspstrong {{.*}} }
+    // none-NOT: attributes #0 = { {{.*}}ssp {{.*}} }
+}
diff --git a/tests/codegen-llvm/static-relocation-model-msvc.rs b/tests/codegen-llvm/static-relocation-model-msvc.rs
new file mode 100644
index 00000000000..4d30e6ec505
--- /dev/null
+++ b/tests/codegen-llvm/static-relocation-model-msvc.rs
@@ -0,0 +1,24 @@
+// Verify linkage of external symbols in the static relocation model on MSVC.
+//
+//@ compile-flags: -Copt-level=3 -C relocation-model=static
+//@ aux-build: extern_decl.rs
+//@ only-x86_64-pc-windows-msvc
+
+#![crate_type = "rlib"]
+
+extern crate extern_decl;
+
+// The `extern_decl` definitions are imported from a statically linked rust
+// crate, thus they are expected to be marked `dso_local` without `dllimport`.
+//
+// The `access_extern()` symbol is from this compilation unit, thus we expect
+// it to be marked `dso_local` as well, given the static relocation model.
+//
+// CHECK: @extern_static = external dso_local local_unnamed_addr global i8
+// CHECK: define dso_local noundef i8 @access_extern() {{.*}}
+// CHECK: declare dso_local noundef i8 @extern_fn() {{.*}}
+
+#[no_mangle]
+pub fn access_extern() -> u8 {
+    unsafe { extern_decl::extern_fn() + extern_decl::extern_static }
+}
diff --git a/tests/codegen-llvm/staticlib-external-inline-fns.rs b/tests/codegen-llvm/staticlib-external-inline-fns.rs
new file mode 100644
index 00000000000..23316a2d9a5
--- /dev/null
+++ b/tests/codegen-llvm/staticlib-external-inline-fns.rs
@@ -0,0 +1,43 @@
+//@ compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "staticlib"]
+
+// CHECK: define{{.*}}void @a()
+#[no_mangle]
+#[inline]
+pub extern "C" fn a() {}
+
+// CHECK: define{{.*}}void @b()
+#[export_name = "b"]
+#[inline]
+pub extern "C" fn b() {}
+
+// CHECK: define{{.*}}void @c()
+#[no_mangle]
+#[inline]
+extern "C" fn c() {}
+
+// CHECK: define{{.*}}void @d()
+#[export_name = "d"]
+#[inline]
+extern "C" fn d() {}
+
+// CHECK: define{{.*}}void @e()
+#[no_mangle]
+#[inline(always)]
+pub extern "C" fn e() {}
+
+// CHECK: define{{.*}}void @f()
+#[export_name = "f"]
+#[inline(always)]
+pub extern "C" fn f() {}
+
+// CHECK: define{{.*}}void @g()
+#[no_mangle]
+#[inline(always)]
+extern "C" fn g() {}
+
+// CHECK: define{{.*}}void @h()
+#[export_name = "h"]
+#[inline(always)]
+extern "C" fn h() {}
diff --git a/tests/codegen-llvm/step_by-overflow-checks.rs b/tests/codegen-llvm/step_by-overflow-checks.rs
new file mode 100644
index 00000000000..53800e9f879
--- /dev/null
+++ b/tests/codegen-llvm/step_by-overflow-checks.rs
@@ -0,0 +1,26 @@
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+
+use std::iter::StepBy;
+use std::slice::Iter;
+
+// The constructor for `StepBy` ensures we can never end up needing to do zero
+// checks on denominators, so check that the code isn't emitting panic paths.
+
+// CHECK-LABEL: @step_by_len_std
+#[no_mangle]
+pub fn step_by_len_std(x: &StepBy<Iter<i32>>) -> usize {
+    // CHECK-NOT: div_by_zero
+    // CHECK: udiv
+    // CHECK-NOT: div_by_zero
+    x.len()
+}
+
+// CHECK-LABEL: @step_by_len_naive
+#[no_mangle]
+pub fn step_by_len_naive(x: Iter<i32>, step_minus_one: usize) -> usize {
+    // CHECK: udiv
+    // CHECK: call{{.+}}div_by_zero
+    x.len() / (step_minus_one + 1)
+}
diff --git a/tests/codegen-llvm/stores.rs b/tests/codegen-llvm/stores.rs
new file mode 100644
index 00000000000..aa3090db6d3
--- /dev/null
+++ b/tests/codegen-llvm/stores.rs
@@ -0,0 +1,35 @@
+//@ compile-flags: -C no-prepopulate-passes
+//
+
+#![crate_type = "lib"]
+
+pub struct Bytes {
+    a: u8,
+    b: u8,
+    c: u8,
+    d: u8,
+}
+
+// CHECK-LABEL: small_array_alignment
+// The array is stored as i32, but its alignment is lower, go with 1 byte to avoid target
+// dependent alignment
+#[no_mangle]
+pub fn small_array_alignment(x: &mut [i8; 4], y: [i8; 4]) {
+    // CHECK: [[TMP:%.+]] = alloca [4 x i8], align 4
+    // CHECK: %y = alloca [4 x i8], align 1
+    // CHECK: store i32 %0, ptr [[TMP]]
+    // CHECK: call void @llvm.memcpy.{{.*}}(ptr align 1 {{.+}}, ptr align 4 {{.+}}, i{{[0-9]+}} 4, i1 false)
+    *x = y;
+}
+
+// CHECK-LABEL: small_struct_alignment
+// The struct is stored as i32, but its alignment is lower, go with 1 byte to avoid target
+// dependent alignment
+#[no_mangle]
+pub fn small_struct_alignment(x: &mut Bytes, y: Bytes) {
+    // CHECK: [[TMP:%.+]] = alloca [4 x i8], align 4
+    // CHECK: %y = alloca [4 x i8], align 1
+    // CHECK: store i32 %0, ptr [[TMP]]
+    // CHECK: call void @llvm.memcpy.{{.*}}(ptr align 1 {{.+}}, ptr align 4 {{.+}}, i{{[0-9]+}} 4, i1 false)
+    *x = y;
+}
diff --git a/tests/codegen-llvm/string-push.rs b/tests/codegen-llvm/string-push.rs
new file mode 100644
index 00000000000..cf5f6bb1aa3
--- /dev/null
+++ b/tests/codegen-llvm/string-push.rs
@@ -0,0 +1,11 @@
+//! Check that `String::push` is optimized enough not to call `memcpy`.
+
+//@ compile-flags: -O
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @string_push_does_not_call_memcpy
+#[no_mangle]
+pub fn string_push_does_not_call_memcpy(s: &mut String, ch: char) {
+    // CHECK-NOT: call void @llvm.memcpy
+    s.push(ch);
+}
diff --git a/tests/codegen-llvm/swap-large-types.rs b/tests/codegen-llvm/swap-large-types.rs
new file mode 100644
index 00000000000..08c486affd9
--- /dev/null
+++ b/tests/codegen-llvm/swap-large-types.rs
@@ -0,0 +1,116 @@
+//@ compile-flags: -Copt-level=3
+//@ only-x86_64
+
+#![crate_type = "lib"]
+
+use std::mem::swap;
+use std::ptr::{copy_nonoverlapping, read, write};
+
+type KeccakBuffer = [[u64; 5]; 5];
+
+// A basic read+copy+write swap implementation ends up copying one of the values
+// to stack for large types, which is completely unnecessary as the lack of
+// overlap means we can just do whatever fits in registers at a time.
+
+// The tests here (after the first one showing that the problem still exists)
+// are less about testing *exactly* what the codegen is, and more about testing
+// 1) That things are swapped directly from one argument to the other,
+//    never going through stack along the way, and
+// 2) That we're doing the swapping for big things using large vector types,
+//    rather then `i64` or `<8 x i8>` (or, even worse, `i8`) at a time.
+//
+// (There are separate tests for intrinsics::typed_swap_nonoverlapping that
+//  check that it, as an intrinsic, are emitting exactly what it should.)
+
+// CHECK-LABEL: @swap_basic
+#[no_mangle]
+pub fn swap_basic(x: &mut KeccakBuffer, y: &mut KeccakBuffer) {
+    // CHECK: alloca [200 x i8]
+
+    // SAFETY: exclusive references are always valid to read/write,
+    // are non-overlapping, and nothing here panics so it's drop-safe.
+    unsafe {
+        let z = read(x);
+        copy_nonoverlapping(y, x, 1);
+        write(y, z);
+    }
+}
+
+// CHECK-LABEL: @swap_std
+#[no_mangle]
+pub fn swap_std(x: &mut KeccakBuffer, y: &mut KeccakBuffer) {
+    // CHECK-NOT: alloca
+    // CHECK: load <{{2|4}} x i64>
+    // CHECK: store <{{2|4}} x i64>
+    swap(x, y)
+}
+
+// CHECK-LABEL: @swap_slice
+#[no_mangle]
+pub fn swap_slice(x: &mut [KeccakBuffer], y: &mut [KeccakBuffer]) {
+    // CHECK-NOT: alloca
+    // CHECK: load <{{2|4}} x i64>
+    // CHECK: store <{{2|4}} x i64>
+    if x.len() == y.len() {
+        x.swap_with_slice(y);
+    }
+}
+
+type OneKilobyteBuffer = [u8; 1024];
+
+// CHECK-LABEL: @swap_1kb_slices
+#[no_mangle]
+pub fn swap_1kb_slices(x: &mut [OneKilobyteBuffer], y: &mut [OneKilobyteBuffer]) {
+    // CHECK-NOT: alloca
+
+    // CHECK-NOT: load i32
+    // CHECK-NOT: store i32
+    // CHECK-NOT: load i16
+    // CHECK-NOT: store i16
+    // CHECK-NOT: load i8
+    // CHECK-NOT: store i8
+
+    // CHECK: load <{{2|4}} x i64>{{.+}}align 1,
+    // CHECK: store <{{2|4}} x i64>{{.+}}align 1,
+
+    // CHECK-NOT: load i32
+    // CHECK-NOT: store i32
+    // CHECK-NOT: load i16
+    // CHECK-NOT: store i16
+    // CHECK-NOT: load i8
+    // CHECK-NOT: store i8
+
+    if x.len() == y.len() {
+        x.swap_with_slice(y);
+    }
+}
+
+#[repr(align(64))]
+pub struct BigButHighlyAligned([u8; 64 * 3]);
+
+// CHECK-LABEL: @swap_big_aligned
+#[no_mangle]
+pub fn swap_big_aligned(x: &mut BigButHighlyAligned, y: &mut BigButHighlyAligned) {
+    // CHECK-NOT: call void @llvm.memcpy
+    // CHECK-NOT: load i32
+    // CHECK-NOT: store i32
+    // CHECK-NOT: load i16
+    // CHECK-NOT: store i16
+    // CHECK-NOT: load i8
+    // CHECK-NOT: store i8
+
+    // CHECK-COUNT-2: load <{{2|4}} x i64>{{.+}}align 64,
+    // CHECK-COUNT-2: store <{{2|4}} x i64>{{.+}}align 64,
+
+    // CHECK-COUNT-2: load <{{2|4}} x i64>{{.+}}align 32,
+    // CHECK-COUNT-2: store <{{2|4}} x i64>{{.+}}align 32,
+
+    // CHECK-NOT: load i32
+    // CHECK-NOT: store i32
+    // CHECK-NOT: load i16
+    // CHECK-NOT: store i16
+    // CHECK-NOT: load i8
+    // CHECK-NOT: store i8
+    // CHECK-NOT: call void @llvm.memcpy
+    swap(x, y)
+}
diff --git a/tests/codegen-llvm/swap-small-types.rs b/tests/codegen-llvm/swap-small-types.rs
new file mode 100644
index 00000000000..7aa613ae9c2
--- /dev/null
+++ b/tests/codegen-llvm/swap-small-types.rs
@@ -0,0 +1,182 @@
+//@ compile-flags: -Copt-level=3 -Z merge-functions=disabled
+//@ only-x86_64
+//@ min-llvm-version: 20
+//@ ignore-std-debug-assertions (`ptr::swap_nonoverlapping` has one which blocks some optimizations)
+
+#![crate_type = "lib"]
+
+use std::mem::swap;
+
+type RGB48 = [u16; 3];
+
+// CHECK-LABEL: @swap_rgb48_manually(
+#[no_mangle]
+pub fn swap_rgb48_manually(x: &mut RGB48, y: &mut RGB48) {
+    // FIXME: See #115212 for why this has an alloca again
+
+    // CHECK: alloca [6 x i8], align 2
+    // CHECK: call void @llvm.memcpy.p0.p0.i64({{.+}}, i64 6, i1 false)
+    // CHECK: call void @llvm.memcpy.p0.p0.i64({{.+}}, i64 6, i1 false)
+    // CHECK: call void @llvm.memcpy.p0.p0.i64({{.+}}, i64 6, i1 false)
+
+    let temp = *x;
+    *x = *y;
+    *y = temp;
+}
+
+// CHECK-LABEL: @swap_rgb48
+#[no_mangle]
+pub fn swap_rgb48(x: &mut RGB48, y: &mut RGB48) {
+    // CHECK-NOT: alloca
+
+    // Swapping `i48` might be cleaner in LLVM-IR here, but `i32`+`i16` isn't bad,
+    // and is closer to the assembly it generates anyway.
+
+    // CHECK-NOT: load{{ }}
+    // CHECK: load i32{{.+}}align 2
+    // CHECK-NEXT: load i32{{.+}}align 2
+    // CHECK-NEXT: store i32{{.+}}align 2
+    // CHECK-NEXT: store i32{{.+}}align 2
+    // CHECK: load i16{{.+}}align 2
+    // CHECK-NEXT: load i16{{.+}}align 2
+    // CHECK-NEXT: store i16{{.+}}align 2
+    // CHECK-NEXT: store i16{{.+}}align 2
+    // CHECK-NOT: store{{ }}
+    swap(x, y)
+}
+
+type RGBA64 = [u16; 4];
+
+// CHECK-LABEL: @swap_rgba64
+#[no_mangle]
+pub fn swap_rgba64(x: &mut RGBA64, y: &mut RGBA64) {
+    // CHECK-NOT: alloca
+    // CHECK-DAG: %[[XVAL:.+]] = load i64, ptr %x, align 2
+    // CHECK-DAG: %[[YVAL:.+]] = load i64, ptr %y, align 2
+    // CHECK-DAG: store i64 %[[YVAL]], ptr %x, align 2
+    // CHECK-DAG: store i64 %[[XVAL]], ptr %y, align 2
+    swap(x, y)
+}
+
+// CHECK-LABEL: @swap_vecs
+#[no_mangle]
+pub fn swap_vecs(x: &mut Vec<u32>, y: &mut Vec<u32>) {
+    // CHECK-NOT: alloca
+    // There are plenty more loads and stores than just these,
+    // but at least one sure better be 64-bit (for size or capacity).
+    // CHECK: load i64
+    // CHECK: load i64
+    // CHECK: store i64
+    // CHECK: store i64
+    // CHECK: ret void
+    swap(x, y)
+}
+
+// CHECK-LABEL: @swap_slices
+#[no_mangle]
+pub fn swap_slices<'a>(x: &mut &'a [u32], y: &mut &'a [u32]) {
+    // CHECK-NOT: alloca
+    // CHECK: load ptr
+    // CHECK: load i64
+    // CHECK: call void @llvm.memcpy.p0.p0.i64({{.+}}, i64 16, i1 false)
+    // CHECK: store ptr
+    // CHECK: store i64
+    swap(x, y)
+}
+
+type RGB24 = [u8; 3];
+
+// CHECK-LABEL: @swap_rgb24_slices
+#[no_mangle]
+pub fn swap_rgb24_slices(x: &mut [RGB24], y: &mut [RGB24]) {
+    // CHECK-NOT: alloca
+
+    // CHECK: mul nuw nsw i64 %{{x|y}}.1, 3
+
+    // CHECK: load <{{[0-9]+}} x i64>
+    // CHECK: store <{{[0-9]+}} x i64>
+
+    // CHECK-COUNT-2: load i32
+    // CHECK-COUNT-2: store i32
+    // CHECK-COUNT-2: load i16
+    // CHECK-COUNT-2: store i16
+    // CHECK-COUNT-2: load i8
+    // CHECK-COUNT-2: store i8
+    if x.len() == y.len() {
+        x.swap_with_slice(y);
+    }
+}
+
+type RGBA32 = [u8; 4];
+
+// CHECK-LABEL: @swap_rgba32_slices
+#[no_mangle]
+pub fn swap_rgba32_slices(x: &mut [RGBA32], y: &mut [RGBA32]) {
+    // CHECK-NOT: alloca
+
+    // Because the size in bytes in a multiple of 4, we can skip the smallest sizes.
+
+    // CHECK: load <{{[0-9]+}} x i64>
+    // CHECK: store <{{[0-9]+}} x i64>
+
+    // CHECK-COUNT-2: load i32
+    // CHECK-COUNT-2: store i32
+
+    // CHECK-NOT: load i16
+    // CHECK-NOT: store i16
+    // CHECK-NOT: load i8
+    // CHECK-NOT: store i8
+
+    if x.len() == y.len() {
+        x.swap_with_slice(y);
+    }
+}
+
+// Strings have a non-power-of-two size, but have pointer alignment,
+// so we swap usizes instead of dropping all the way down to bytes.
+const _: () = assert!(!std::mem::size_of::<String>().is_power_of_two());
+
+// CHECK-LABEL: @swap_string_slices
+#[no_mangle]
+pub fn swap_string_slices(x: &mut [String], y: &mut [String]) {
+    // CHECK-NOT: alloca
+    // CHECK: load <{{[0-9]+}} x i64>{{.+}}, align 8,
+    // CHECK: store <{{[0-9]+}} x i64>{{.+}}, align 8,
+    if x.len() == y.len() {
+        x.swap_with_slice(y);
+    }
+}
+
+#[repr(C, packed)]
+pub struct Packed {
+    pub first: bool,
+    pub second: usize,
+}
+
+// CHECK-LABEL: @swap_packed_structs
+#[no_mangle]
+pub fn swap_packed_structs(x: &mut Packed, y: &mut Packed) {
+    // CHECK-NOT: alloca
+
+    // CHECK-NOT: load
+    // CHECK-NOT: store
+
+    // CHECK: %[[A:.+]] = load i64, ptr %x, align 1,
+    // CHECK-NEXT: %[[B:.+]] = load i64, ptr %y, align 1,
+    // CHECK-NEXT: store i64 %[[B]], ptr %x, align 1,
+    // CHECK-NEXT: store i64 %[[A]], ptr %y, align 1,
+
+    // CHECK-NOT: load
+    // CHECK-NOT: store
+
+    // CHECK: %[[C:.+]] = load i8, ptr %[[X8:.+]], align 1,
+    // CHECK-NEXT: %[[D:.+]] = load i8, ptr %[[Y8:.+]], align 1,
+    // CHECK-NEXT: store i8 %[[D]], ptr %[[X8]], align 1,
+    // CHECK-NEXT: store i8 %[[C]], ptr %[[Y8]], align 1,
+
+    // CHECK-NOT: load
+    // CHECK-NOT: store
+
+    // CHECK: ret void
+    swap(x, y)
+}
diff --git a/tests/codegen-llvm/target-cpu-on-functions.rs b/tests/codegen-llvm/target-cpu-on-functions.rs
new file mode 100644
index 00000000000..25c10e7ce44
--- /dev/null
+++ b/tests/codegen-llvm/target-cpu-on-functions.rs
@@ -0,0 +1,22 @@
+// This test makes sure that functions get annotated with the proper
+// "target-cpu" attribute in LLVM.
+
+//@ no-prefer-dynamic
+//
+//@ compile-flags: -C no-prepopulate-passes -C panic=abort -C linker-plugin-lto -Cpasses=name-anon-globals
+
+#![crate_type = "staticlib"]
+
+// CHECK-LABEL: define {{.*}} @exported() {{.*}} #0
+#[no_mangle]
+pub extern "C" fn exported() {
+    not_exported();
+}
+
+// CHECK-LABEL: ; target_cpu_on_functions::not_exported
+// CHECK-NEXT: ; Function Attrs:
+// CHECK-NEXT: define {{.*}}() {{.*}} #1
+#[inline(never)]
+fn not_exported() {}
+
+// CHECK: attributes #0 = {{.*}} "target-cpu"="{{.*}}"
diff --git a/tests/codegen-llvm/target-feature-inline-closure.rs b/tests/codegen-llvm/target-feature-inline-closure.rs
new file mode 100644
index 00000000000..5d54444f994
--- /dev/null
+++ b/tests/codegen-llvm/target-feature-inline-closure.rs
@@ -0,0 +1,33 @@
+//@ only-x86_64
+// Set the base cpu explicitly, in case the default has been changed.
+//@ compile-flags: -Copt-level=3 -Ctarget-cpu=x86-64
+
+#![crate_type = "lib"]
+
+#[cfg(target_arch = "x86_64")]
+use std::arch::x86_64::*;
+
+// CHECK-LABEL: @with_avx
+#[no_mangle]
+#[cfg(target_arch = "x86_64")]
+#[target_feature(enable = "avx")]
+fn with_avx(x: __m256) -> __m256 {
+    // CHECK: fadd <8 x float>
+    let add = {
+        #[inline(always)]
+        |x, y| unsafe { _mm256_add_ps(x, y) }
+    };
+    add(x, x)
+}
+
+// CHECK-LABEL: @without_avx
+#[no_mangle]
+#[cfg(target_arch = "x86_64")]
+unsafe fn without_avx(x: __m256) -> __m256 {
+    // CHECK-NOT: fadd <8 x float>
+    let add = {
+        #[inline(always)]
+        |x, y| unsafe { _mm256_add_ps(x, y) }
+    };
+    add(x, x)
+}
diff --git a/tests/codegen-llvm/target-feature-negative-implication.rs b/tests/codegen-llvm/target-feature-negative-implication.rs
new file mode 100644
index 00000000000..36cd82dd8cf
--- /dev/null
+++ b/tests/codegen-llvm/target-feature-negative-implication.rs
@@ -0,0 +1,20 @@
+//@ add-core-stubs
+//@ needs-llvm-components: x86
+//@ compile-flags: --target=x86_64-unknown-linux-gnu
+//@ compile-flags: -Ctarget-feature=-avx2
+
+#![feature(no_core, lang_items)]
+#![crate_type = "lib"]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+#[no_mangle]
+pub unsafe fn banana() {
+    // CHECK-LABEL: @banana()
+    // CHECK-SAME: [[BANANAATTRS:#[0-9]+]] {
+}
+
+// CHECK: attributes [[BANANAATTRS]]
+// CHECK-SAME: -avx512
diff --git a/tests/codegen-llvm/target-feature-overrides.rs b/tests/codegen-llvm/target-feature-overrides.rs
new file mode 100644
index 00000000000..63a586d388b
--- /dev/null
+++ b/tests/codegen-llvm/target-feature-overrides.rs
@@ -0,0 +1,46 @@
+// ignore-tidy-linelength
+//@ add-core-stubs
+//@ revisions: COMPAT INCOMPAT
+//@ needs-llvm-components: x86
+//@ compile-flags: --target=x86_64-unknown-linux-gnu -Copt-level=3
+//@ [COMPAT] compile-flags: -Ctarget-feature=+avx2
+//@ [INCOMPAT] compile-flags: -Ctarget-feature=-avx2,-avx
+
+// See also tests/assembly-llvm/target-feature-multiple.rs
+#![feature(no_core, lang_items)]
+#![crate_type = "lib"]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+extern "C" {
+    fn peach() -> u32;
+}
+
+#[inline]
+#[target_feature(enable = "avx")]
+#[no_mangle]
+pub unsafe fn apple() -> u32 {
+    // CHECK-LABEL: @apple()
+    // CHECK-SAME: [[APPLEATTRS:#[0-9]+]] {
+    // CHECK: {{.*}}call{{.*}}@peach
+    peach()
+}
+
+// target features same as global
+#[no_mangle]
+pub unsafe fn banana() -> u32 {
+    // CHECK-LABEL: @banana()
+    // CHECK-SAME: [[BANANAATTRS:#[0-9]+]] {
+    // COMPAT: {{.*}}call{{.*}}@peach
+    // INCOMPAT: {{.*}}call{{.*}}@apple
+    apple() // Compatible for inline in COMPAT revision and can't be inlined in INCOMPAT
+}
+
+// CHECK: attributes [[APPLEATTRS]]
+// COMPAT-SAME: "target-features"="+avx,+avx2,{{.*}}"
+// INCOMPAT-SAME: "target-features"="{{(-[^,]+,)*}}-avx2{{(,-[^,]+)*}},-avx{{(,-[^,]+)*}},+avx{{(,\+[^,]+)*}}"
+// CHECK: attributes [[BANANAATTRS]]
+// COMPAT-SAME: "target-features"="+avx,+avx2,{{.*}}"
+// INCOMPAT-SAME: "target-features"="{{(-[^,]+,)*}}-avx2{{(,-[^,]+)*}},-avx{{(,-[^,]+)*}}"
diff --git a/tests/codegen-llvm/terminating-catchpad.rs b/tests/codegen-llvm/terminating-catchpad.rs
new file mode 100644
index 00000000000..a2ec19871d1
--- /dev/null
+++ b/tests/codegen-llvm/terminating-catchpad.rs
@@ -0,0 +1,43 @@
+//@ revisions: emscripten wasi seh
+//@[emscripten] compile-flags: --target wasm32-unknown-emscripten -Z emscripten-wasm-eh
+//@[wasi] compile-flags: --target wasm32-wasip1 -C panic=unwind
+//@[seh] compile-flags: --target x86_64-pc-windows-msvc
+//@[emscripten] needs-llvm-components: webassembly
+//@[wasi] needs-llvm-components: webassembly
+//@[seh] needs-llvm-components: x86
+
+// Ensure a catch-all generates:
+// - `catchpad ... [ptr null]` on Wasm (otherwise LLVM gets confused)
+// - `catchpad ... [ptr null, i32 64, ptr null]` on Windows (otherwise we catch SEH exceptions)
+
+#![feature(no_core, lang_items, rustc_attrs)]
+#![crate_type = "lib"]
+#![no_std]
+#![no_core]
+
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
+#[lang = "sized"]
+pub trait Sized: MetaSized {}
+
+unsafe extern "C-unwind" {
+    safe fn unwinds();
+}
+
+#[lang = "panic_cannot_unwind"]
+fn panic_cannot_unwind() -> ! {
+    loop {}
+}
+
+#[no_mangle]
+#[rustc_nounwind]
+pub fn doesnt_unwind() {
+    // emscripten: %catchpad = catchpad within %catchswitch [ptr null]
+    // wasi: %catchpad = catchpad within %catchswitch [ptr null]
+    // seh: %catchpad = catchpad within %catchswitch [ptr null, i32 64, ptr null]
+    unwinds();
+}
diff --git a/tests/codegen-llvm/thread-local.rs b/tests/codegen-llvm/thread-local.rs
new file mode 100644
index 00000000000..41df8c9be1b
--- /dev/null
+++ b/tests/codegen-llvm/thread-local.rs
@@ -0,0 +1,54 @@
+//@ compile-flags: -Copt-level=3
+//@ aux-build:thread_local_aux.rs
+//@ ignore-windows FIXME(#134939)
+//@ ignore-wasm globals are used instead of thread locals
+//@ ignore-emscripten globals are used instead of thread locals
+//@ ignore-android does not use #[thread_local]
+//@ ignore-nto does not use #[thread_local]
+
+#![crate_type = "lib"]
+
+extern crate thread_local_aux as aux;
+
+use std::cell::Cell;
+
+thread_local!(static A: Cell<u32> = const { Cell::new(1) });
+
+// CHECK: [[TLS_AUX:@.+]] = external thread_local{{.*}} global i64
+// CHECK: [[TLS:@.+]] = internal thread_local{{.*}} global
+
+// CHECK-LABEL: @get
+#[no_mangle]
+fn get() -> u32 {
+    // CHECK: [[PTR:%.+]] = tail call {{.*}} ptr @llvm.threadlocal.address.p0(ptr [[TLS]])
+    // CHECK-NEXT: [[RET_0:%.+]] = load i32, ptr [[PTR]]
+    // CHECK-NEXT: ret i32 [[RET_0]]
+    A.with(|a| a.get())
+}
+
+// CHECK-LABEL: @set
+#[no_mangle]
+fn set(v: u32) {
+    // CHECK: [[PTR:%.+]] = tail call {{.*}} ptr @llvm.threadlocal.address.p0(ptr [[TLS]])
+    // CHECK-NEXT: store i32 %0, ptr [[PTR]]
+    // CHECK-NEXT: ret void
+    A.with(|a| a.set(v))
+}
+
+// CHECK-LABEL: @get_aux
+#[no_mangle]
+fn get_aux() -> u64 {
+    // CHECK: [[PTR:%.+]] = tail call {{.*}} ptr @llvm.threadlocal.address.p0(ptr [[TLS_AUX]])
+    // CHECK-NEXT: [[RET_1:%.+]] = load i64, ptr [[PTR]]
+    // CHECK-NEXT: ret i64 [[RET_1]]
+    aux::A.with(|a| a.get())
+}
+
+// CHECK-LABEL: @set_aux
+#[no_mangle]
+fn set_aux(v: u64) {
+    // CHECK: [[PTR:%.+]] = tail call {{.*}} ptr @llvm.threadlocal.address.p0(ptr [[TLS_AUX]])
+    // CHECK-NEXT: store i64 %0, ptr [[PTR]]
+    // CHECK-NEXT: ret void
+    aux::A.with(|a| a.set(v))
+}
diff --git a/tests/codegen-llvm/tied-features-strength.rs b/tests/codegen-llvm/tied-features-strength.rs
new file mode 100644
index 00000000000..81499c070d1
--- /dev/null
+++ b/tests/codegen-llvm/tied-features-strength.rs
@@ -0,0 +1,34 @@
+// ignore-tidy-linelength
+//@ add-core-stubs
+//@ revisions: ENABLE_SVE DISABLE_SVE DISABLE_NEON ENABLE_NEON
+//@ compile-flags: --crate-type=rlib --target=aarch64-unknown-linux-gnu
+//@ needs-llvm-components: aarch64
+
+// Rust made SVE require neon.
+//@ [ENABLE_SVE] compile-flags: -C target-feature=+sve -Copt-level=0
+// ENABLE_SVE: attributes #0
+// ENABLE_SVE-SAME: +neon
+// ENABLE_SVE-SAME: +sve
+
+// However, disabling SVE does not disable neon.
+//@ [DISABLE_SVE] compile-flags: -C target-feature=-sve -Copt-level=0
+// DISABLE_SVE: attributes #0
+// DISABLE_SVE-NOT: -neon
+// DISABLE_SVE-SAME: -sve
+
+// OTOH, neon fn `fp-armv8` are fully tied; toggling neon must toggle `fp-armv8` the same way.
+//@ [DISABLE_NEON] compile-flags: -C target-feature=-neon -Copt-level=0
+// DISABLE_NEON: attributes #0
+// DISABLE_NEON-SAME: -neon
+// DISABLE_NEON-SAME: -fp-armv8
+
+//@ [ENABLE_NEON] compile-flags: -C target-feature=+neon -Copt-level=0
+// ENABLE_NEON: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(\+fp-armv8,?)|(\+neon,?))*}}" }
+
+#![feature(no_core, lang_items)]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+pub fn test() {}
diff --git a/tests/codegen-llvm/to_vec.rs b/tests/codegen-llvm/to_vec.rs
new file mode 100644
index 00000000000..4f6e77188d8
--- /dev/null
+++ b/tests/codegen-llvm/to_vec.rs
@@ -0,0 +1,10 @@
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @copy_to_vec
+#[no_mangle]
+fn copy_to_vec(s: &[u64]) -> Vec<u64> {
+    s.to_vec()
+    // CHECK: call void @llvm.memcpy
+}
diff --git a/tests/codegen-llvm/trailing_zeros.rs b/tests/codegen-llvm/trailing_zeros.rs
new file mode 100644
index 00000000000..0816a980992
--- /dev/null
+++ b/tests/codegen-llvm/trailing_zeros.rs
@@ -0,0 +1,21 @@
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @trailing_zeros_ge
+#[no_mangle]
+pub fn trailing_zeros_ge(val: u32) -> bool {
+    // CHECK: %[[AND:.*]] = and i32 %val, 7
+    // CHECK: %[[ICMP:.*]] = icmp eq i32 %[[AND]], 0
+    // CHECK: ret i1 %[[ICMP]]
+    val.trailing_zeros() >= 3
+}
+
+// CHECK-LABEL: @trailing_zeros_gt
+#[no_mangle]
+pub fn trailing_zeros_gt(val: u64) -> bool {
+    // CHECK: %[[AND:.*]] = and i64 %val, 15
+    // CHECK: %[[ICMP:.*]] = icmp eq i64 %[[AND]], 0
+    // CHECK: ret i1 %[[ICMP]]
+    val.trailing_zeros() > 3
+}
diff --git a/tests/codegen-llvm/transmute-optimized.rs b/tests/codegen-llvm/transmute-optimized.rs
new file mode 100644
index 00000000000..477fdc6de90
--- /dev/null
+++ b/tests/codegen-llvm/transmute-optimized.rs
@@ -0,0 +1,120 @@
+//@ compile-flags: -Copt-level=3 -Z merge-functions=disabled
+#![crate_type = "lib"]
+
+// This tests that LLVM can optimize based on the niches in the source or
+// destination types for transmutes.
+
+#[repr(u32)]
+pub enum AlwaysZero32 {
+    X = 0,
+}
+
+// CHECK-LABEL: i32 @issue_109958(i32
+#[no_mangle]
+pub fn issue_109958(x: AlwaysZero32) -> i32 {
+    // CHECK: ret i32 0
+    unsafe { std::mem::transmute(x) }
+}
+
+// CHECK-LABEL: i1 @reference_is_null(ptr
+#[no_mangle]
+pub fn reference_is_null(x: &i32) -> bool {
+    // CHECK: ret i1 false
+    let p: *const i32 = unsafe { std::mem::transmute(x) };
+    p.is_null()
+}
+
+// CHECK-LABEL: i1 @non_null_is_null(ptr
+#[no_mangle]
+pub fn non_null_is_null(x: std::ptr::NonNull<i32>) -> bool {
+    // CHECK: ret i1 false
+    let p: *const i32 = unsafe { std::mem::transmute(x) };
+    p.is_null()
+}
+
+// CHECK-LABEL: i1 @non_zero_is_null(
+#[no_mangle]
+pub fn non_zero_is_null(x: std::num::NonZero<usize>) -> bool {
+    // CHECK: ret i1 false
+    let p: *const i32 = unsafe { std::mem::transmute(x) };
+    p.is_null()
+}
+
+// CHECK-LABEL: i1 @non_null_is_zero(ptr
+#[no_mangle]
+pub fn non_null_is_zero(x: std::ptr::NonNull<i32>) -> bool {
+    // CHECK: ret i1 false
+    let a: isize = unsafe { std::mem::transmute(x) };
+    a == 0
+}
+
+// CHECK-LABEL: i1 @bool_ordering_is_ge(i1
+#[no_mangle]
+pub fn bool_ordering_is_ge(x: bool) -> bool {
+    // CHECK: ret i1 true
+    let y: std::cmp::Ordering = unsafe { std::mem::transmute(x) };
+    y.is_ge()
+}
+
+// CHECK-LABEL: i1 @ordering_is_ge_then_transmute_to_bool(i8
+#[no_mangle]
+pub fn ordering_is_ge_then_transmute_to_bool(x: std::cmp::Ordering) -> bool {
+    let r = x.is_ge();
+    let _: bool = unsafe { std::mem::transmute(x) };
+    r
+}
+
+// CHECK-LABEL: i32 @normal_div(i32
+#[no_mangle]
+pub fn normal_div(a: u32, b: u32) -> u32 {
+    // CHECK: call core::panicking::panic
+    a / b
+}
+
+// CHECK-LABEL: i32 @div_transmute_nonzero(i32
+#[no_mangle]
+pub fn div_transmute_nonzero(a: u32, b: std::num::NonZero<i32>) -> u32 {
+    // CHECK-NOT: call core::panicking::panic
+    // CHECK: %[[R:.+]] = udiv i32 %a, %b
+    // CHECK-NEXT: ret i32 %[[R]]
+    // CHECK-NOT: call core::panicking::panic
+    let d: u32 = unsafe { std::mem::transmute(b) };
+    a / d
+}
+
+#[repr(i8)]
+pub enum OneTwoThree {
+    One = 1,
+    Two = 2,
+    Three = 3,
+}
+
+// CHECK-LABEL: i8 @ordering_transmute_onetwothree(i8
+#[no_mangle]
+pub unsafe fn ordering_transmute_onetwothree(x: std::cmp::Ordering) -> OneTwoThree {
+    // CHECK: ret i8 1
+    std::mem::transmute(x)
+}
+
+// CHECK-LABEL: i8 @onetwothree_transmute_ordering(i8
+#[no_mangle]
+pub unsafe fn onetwothree_transmute_ordering(x: OneTwoThree) -> std::cmp::Ordering {
+    // CHECK: ret i8 1
+    std::mem::transmute(x)
+}
+
+// CHECK-LABEL: i1 @char_is_negative(i32
+#[no_mangle]
+pub fn char_is_negative(c: char) -> bool {
+    // CHECK: ret i1 false
+    let x: i32 = unsafe { std::mem::transmute(c) };
+    x < 0
+}
+
+// CHECK-LABEL: i1 @transmute_to_char_is_negative(i32
+#[no_mangle]
+pub fn transmute_to_char_is_negative(x: i32) -> bool {
+    // CHECK: ret i1 false
+    let _c: char = unsafe { std::mem::transmute(x) };
+    x < 0
+}
diff --git a/tests/codegen-llvm/transmute-scalar.rs b/tests/codegen-llvm/transmute-scalar.rs
new file mode 100644
index 00000000000..ce1b0558b2e
--- /dev/null
+++ b/tests/codegen-llvm/transmute-scalar.rs
@@ -0,0 +1,143 @@
+//@ add-core-stubs
+//@ compile-flags: -C opt-level=0 -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+#![feature(no_core, repr_simd, arm_target_feature, mips_target_feature, s390x_target_feature)]
+#![no_core]
+extern crate minicore;
+
+use minicore::*;
+
+// With opaque ptrs in LLVM, `transmute` can load/store any `alloca` as any type,
+// without needing to pointercast, and SRoA will turn that into a `bitcast`.
+// Thus memory-to-memory transmutes don't need to generate them ourselves.
+
+// However, `bitcast`s and `ptrtoint`s and `inttoptr`s are still worth doing when
+// that allows us to avoid the `alloca`s entirely; see `rvalue_creates_operand`.
+
+// CHECK-LABEL: define{{.*}}i32 @f32_to_bits(float %x)
+// CHECK: %_0 = bitcast float %x to i32
+// CHECK-NEXT: ret i32 %_0
+#[no_mangle]
+pub fn f32_to_bits(x: f32) -> u32 {
+    unsafe { mem::transmute(x) }
+}
+
+// CHECK-LABEL: define{{.*}}i8 @bool_to_byte(i1 zeroext %b)
+// CHECK: %_0 = zext i1 %b to i8
+// CHECK-NEXT: ret i8 %_0
+#[no_mangle]
+pub fn bool_to_byte(b: bool) -> u8 {
+    unsafe { mem::transmute(b) }
+}
+
+// CHECK-LABEL: define{{.*}}zeroext i1 @byte_to_bool(i8{{.*}} %byte)
+// CHECK: %_0 = trunc{{( nuw)?}} i8 %byte to i1
+// CHECK-NEXT: ret i1 %_0
+#[no_mangle]
+pub unsafe fn byte_to_bool(byte: u8) -> bool {
+    mem::transmute(byte)
+}
+
+// CHECK-LABEL: define{{.*}}ptr @ptr_to_ptr(ptr %p)
+// CHECK: ret ptr %p
+#[no_mangle]
+pub fn ptr_to_ptr(p: *mut u16) -> *mut u8 {
+    unsafe { mem::transmute(p) }
+}
+
+// CHECK: define{{.*}}[[USIZE:i[0-9]+]] @ptr_to_int(ptr %p)
+// CHECK: %_0 = ptrtoint ptr %p to [[USIZE]]
+// CHECK-NEXT: ret [[USIZE]] %_0
+#[no_mangle]
+pub fn ptr_to_int(p: *mut u16) -> usize {
+    unsafe { mem::transmute(p) }
+}
+
+// CHECK: define{{.*}}ptr @int_to_ptr([[USIZE]] %i)
+// CHECK: %_0 = getelementptr i8, ptr null, [[USIZE]] %i
+// CHECK-NEXT: ret ptr %_0
+#[no_mangle]
+pub fn int_to_ptr(i: usize) -> *mut u16 {
+    unsafe { mem::transmute(i) }
+}
+
+// This is the one case where signedness matters to transmuting:
+// the LLVM type is `i8` here because of `repr(i8)`,
+// whereas below with the `repr(u8)` it's `i1` in LLVM instead.
+#[repr(i8)]
+pub enum FakeBoolSigned {
+    False = 0,
+    True = 1,
+}
+
+// CHECK-LABEL: define{{.*}}i8 @bool_to_fake_bool_signed(i1 zeroext %b)
+// CHECK: %_0 = zext i1 %b to i8
+// CHECK-NEXT: ret i8 %_0
+#[no_mangle]
+pub fn bool_to_fake_bool_signed(b: bool) -> FakeBoolSigned {
+    unsafe { mem::transmute(b) }
+}
+
+// CHECK-LABEL: define{{.*}}i1 @fake_bool_signed_to_bool(i8 %b)
+// CHECK: %_0 = trunc nuw i8 %b to i1
+// CHECK-NEXT: ret i1 %_0
+#[no_mangle]
+pub fn fake_bool_signed_to_bool(b: FakeBoolSigned) -> bool {
+    unsafe { mem::transmute(b) }
+}
+
+#[repr(u8)]
+pub enum FakeBoolUnsigned {
+    False = 0,
+    True = 1,
+}
+
+// CHECK-LABEL: define{{.*}}i1 @bool_to_fake_bool_unsigned(i1 zeroext %b)
+// CHECK: ret i1 %b
+#[no_mangle]
+pub fn bool_to_fake_bool_unsigned(b: bool) -> FakeBoolUnsigned {
+    unsafe { mem::transmute(b) }
+}
+
+// CHECK-LABEL: define{{.*}}i1 @fake_bool_unsigned_to_bool(i1 zeroext %b)
+// CHECK: ret i1 %b
+#[no_mangle]
+pub fn fake_bool_unsigned_to_bool(b: FakeBoolUnsigned) -> bool {
+    unsafe { mem::transmute(b) }
+}
+
+#[repr(simd)]
+struct S([i64; 1]);
+
+// CHECK-LABEL: define{{.*}}i64 @single_element_simd_to_scalar(<1 x i64> %b)
+// CHECK-NEXT: start:
+// CHECK-NEXT: %[[RET:.+]] = alloca [8 x i8]
+// CHECK-NEXT: store <1 x i64> %b, ptr %[[RET]]
+// CHECK-NEXT: %[[TEMP:.+]] = load i64, ptr %[[RET]]
+// CHECK-NEXT: ret i64 %[[TEMP]]
+#[no_mangle]
+#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))]
+#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))]
+#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))]
+#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))]
+#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))]
+pub extern "C" fn single_element_simd_to_scalar(b: S) -> i64 {
+    unsafe { mem::transmute(b) }
+}
+
+// CHECK-LABEL: define{{.*}}<1 x i64> @scalar_to_single_element_simd(i64 %b)
+// CHECK-NEXT: start:
+// CHECK-NEXT: %[[RET:.+]] = alloca [8 x i8]
+// CHECK-NEXT: store i64 %b, ptr %[[RET]]
+// CHECK-NEXT: %[[TEMP:.+]] = load <1 x i64>, ptr %[[RET]]
+// CHECK-NEXT: ret <1 x i64> %[[TEMP]]
+#[no_mangle]
+#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))]
+#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))]
+#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))]
+#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))]
+#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))]
+pub extern "C" fn scalar_to_single_element_simd(b: i64) -> S {
+    unsafe { mem::transmute(b) }
+}
diff --git a/tests/codegen-llvm/try_question_mark_nop.rs b/tests/codegen-llvm/try_question_mark_nop.rs
new file mode 100644
index 00000000000..398c9a580bc
--- /dev/null
+++ b/tests/codegen-llvm/try_question_mark_nop.rs
@@ -0,0 +1,243 @@
+//@ compile-flags: -Copt-level=3 -Z merge-functions=disabled
+//@ edition: 2021
+//@ only-x86_64
+//@ revisions: NINETEEN TWENTY
+//@[NINETEEN] exact-llvm-major-version: 19
+//@[TWENTY] min-llvm-version: 20
+
+#![crate_type = "lib"]
+#![feature(try_blocks)]
+
+use std::ops::ControlFlow::{self, Break, Continue};
+use std::ptr::NonNull;
+
+// CHECK-LABEL: @option_nop_match_32
+#[no_mangle]
+pub fn option_nop_match_32(x: Option<u32>) -> Option<u32> {
+    // CHECK: start:
+    // CHECK-NEXT: [[TRUNC:%.*]] = trunc nuw i32 %0 to i1
+
+    // NINETEEN-NEXT: [[SELECT:%.*]] = select i1 [[TRUNC]], i32 %0, i32 0
+    // NINETEEN-NEXT: [[REG2:%.*]] = insertvalue { i32, i32 } poison, i32 [[SELECT]], 0
+    // NINETEEN-NEXT: [[REG3:%.*]] = insertvalue { i32, i32 } [[REG2]], i32 %1, 1
+
+    // TWENTY-NEXT: [[SELECT:%.*]] = select i1 [[TRUNC]], i32 %1, i32 undef
+    // TWENTY-NEXT: [[REG2:%.*]] = insertvalue { i32, i32 } poison, i32 %0, 0
+    // TWENTY-NEXT: [[REG3:%.*]] = insertvalue { i32, i32 } [[REG2]], i32 [[SELECT]], 1
+
+    // CHECK-NEXT: ret { i32, i32 } [[REG3]]
+    match x {
+        Some(x) => Some(x),
+        None => None,
+    }
+}
+
+// CHECK-LABEL: @option_nop_traits_32
+#[no_mangle]
+pub fn option_nop_traits_32(x: Option<u32>) -> Option<u32> {
+    // CHECK: start:
+    // TWENTY-NEXT: %[[IS_SOME:.+]] = trunc nuw i32 %0 to i1
+    // TWENTY-NEXT: select i1 %[[IS_SOME]], i32 %1, i32 undef
+    // CHECK-NEXT: insertvalue { i32, i32 }
+    // CHECK-NEXT: insertvalue { i32, i32 }
+    // CHECK-NEXT: ret { i32, i32 }
+    try { x? }
+}
+
+// CHECK-LABEL: @result_nop_match_32
+#[no_mangle]
+pub fn result_nop_match_32(x: Result<i32, u32>) -> Result<i32, u32> {
+    // CHECK: start:
+    // CHECK-NEXT: insertvalue { i32, i32 }
+    // CHECK-NEXT: insertvalue { i32, i32 }
+    // CHECK-NEXT: ret { i32, i32 }
+    match x {
+        Ok(x) => Ok(x),
+        Err(x) => Err(x),
+    }
+}
+
+// CHECK-LABEL: @result_nop_traits_32
+#[no_mangle]
+pub fn result_nop_traits_32(x: Result<i32, u32>) -> Result<i32, u32> {
+    // CHECK: start:
+    // CHECK-NEXT: insertvalue { i32, i32 }
+    // CHECK-NEXT: insertvalue { i32, i32 }
+    // CHECK-NEXT: ret { i32, i32 }
+    try { x? }
+}
+
+// CHECK-LABEL: @control_flow_nop_match_32
+#[no_mangle]
+pub fn control_flow_nop_match_32(x: ControlFlow<i32, u32>) -> ControlFlow<i32, u32> {
+    // CHECK: start:
+    // CHECK-NEXT: insertvalue { i32, i32 }
+    // CHECK-NEXT: insertvalue { i32, i32 }
+    // CHECK-NEXT: ret { i32, i32 }
+    match x {
+        Continue(x) => Continue(x),
+        Break(x) => Break(x),
+    }
+}
+
+// CHECK-LABEL: @control_flow_nop_traits_32
+#[no_mangle]
+pub fn control_flow_nop_traits_32(x: ControlFlow<i32, u32>) -> ControlFlow<i32, u32> {
+    // CHECK: start:
+    // CHECK-NEXT: insertvalue { i32, i32 }
+    // CHECK-NEXT: insertvalue { i32, i32 }
+    // CHECK-NEXT: ret { i32, i32 }
+    try { x? }
+}
+
+// CHECK-LABEL: @option_nop_match_64
+#[no_mangle]
+pub fn option_nop_match_64(x: Option<u64>) -> Option<u64> {
+    // CHECK: start:
+    // CHECK-NEXT: [[TRUNC:%.*]] = trunc nuw i64 %0 to i1
+
+    // NINETEEN-NEXT: [[SELECT:%.*]] = select i1 [[TRUNC]], i64 %0, i64 0
+    // NINETEEN-NEXT: [[REG2:%.*]] = insertvalue { i64, i64 } poison, i64 [[SELECT]], 0
+    // NINETEEN-NEXT: [[REG3:%.*]] = insertvalue { i64, i64 } [[REG2]], i64 %1, 1
+
+    // TWENTY-NEXT: [[SELECT:%.*]] = select i1 [[TRUNC]], i64 %1, i64 undef
+    // TWENTY-NEXT: [[REG2:%.*]] = insertvalue { i64, i64 } poison, i64 %0, 0
+    // TWENTY-NEXT: [[REG3:%.*]] = insertvalue { i64, i64 } [[REG2]], i64 [[SELECT]], 1
+
+    // CHECK-NEXT: ret { i64, i64 } [[REG3]]
+    match x {
+        Some(x) => Some(x),
+        None => None,
+    }
+}
+
+// CHECK-LABEL: @option_nop_traits_64
+#[no_mangle]
+pub fn option_nop_traits_64(x: Option<u64>) -> Option<u64> {
+    // CHECK: start:
+    // TWENTY-NEXT: %[[TRUNC:[0-9]+]] = trunc nuw i64 %0 to i1
+    // TWENTY-NEXT: %[[SEL:\.[0-9]+]] = select i1 %[[TRUNC]], i64 %1, i64 undef
+    // CHECK-NEXT: insertvalue { i64, i64 }
+    // CHECK-NEXT: insertvalue { i64, i64 }
+    // CHECK-NEXT: ret { i64, i64 }
+    try { x? }
+}
+
+// CHECK-LABEL: @result_nop_match_64
+#[no_mangle]
+pub fn result_nop_match_64(x: Result<i64, u64>) -> Result<i64, u64> {
+    // CHECK: start:
+    // CHECK-NEXT: insertvalue { i64, i64 }
+    // CHECK-NEXT: insertvalue { i64, i64 }
+    // CHECK-NEXT: ret { i64, i64 }
+    match x {
+        Ok(x) => Ok(x),
+        Err(x) => Err(x),
+    }
+}
+
+// CHECK-LABEL: @result_nop_traits_64
+#[no_mangle]
+pub fn result_nop_traits_64(x: Result<i64, u64>) -> Result<i64, u64> {
+    // CHECK: start:
+    // CHECK-NEXT: insertvalue { i64, i64 }
+    // CHECK-NEXT: insertvalue { i64, i64 }
+    // CHECK-NEXT: ret { i64, i64 }
+    try { x? }
+}
+
+// CHECK-LABEL: @control_flow_nop_match_64
+#[no_mangle]
+pub fn control_flow_nop_match_64(x: ControlFlow<i64, u64>) -> ControlFlow<i64, u64> {
+    // CHECK: start:
+    // CHECK-NEXT: insertvalue { i64, i64 }
+    // CHECK-NEXT: insertvalue { i64, i64 }
+    // CHECK-NEXT: ret { i64, i64 }
+    match x {
+        Continue(x) => Continue(x),
+        Break(x) => Break(x),
+    }
+}
+
+// CHECK-LABEL: @control_flow_nop_traits_64
+#[no_mangle]
+pub fn control_flow_nop_traits_64(x: ControlFlow<i64, u64>) -> ControlFlow<i64, u64> {
+    // CHECK: start:
+    // CHECK-NEXT: insertvalue { i64, i64 }
+    // CHECK-NEXT: insertvalue { i64, i64 }
+    // CHECK-NEXT: ret { i64, i64 }
+    try { x? }
+}
+
+// CHECK-LABEL: @result_nop_match_128
+#[no_mangle]
+pub fn result_nop_match_128(x: Result<i128, u128>) -> Result<i128, u128> {
+    // CHECK: start:
+    // CHECK-NEXT: store i128
+    // CHECK-NEXT: getelementptr inbounds {{(nuw )?}}i8
+    // CHECK-NEXT: store i128
+    // CHECK-NEXT: ret void
+    match x {
+        Ok(x) => Ok(x),
+        Err(x) => Err(x),
+    }
+}
+
+// CHECK-LABEL: @result_nop_traits_128
+#[no_mangle]
+pub fn result_nop_traits_128(x: Result<i128, u128>) -> Result<i128, u128> {
+    // CHECK: start:
+    // CHECK-NEXT: getelementptr inbounds {{(nuw )?}}i8
+    // CHECK-NEXT: store i128
+    // CHECK-NEXT: store i128
+    // CHECK-NEXT: ret void
+    try { x? }
+}
+
+// CHECK-LABEL: @control_flow_nop_match_128
+#[no_mangle]
+pub fn control_flow_nop_match_128(x: ControlFlow<i128, u128>) -> ControlFlow<i128, u128> {
+    // CHECK: start:
+    // CHECK-NEXT: store i128
+    // CHECK-NEXT: getelementptr inbounds {{(nuw )?}}i8
+    // CHECK-NEXT: store i128
+    // CHECK-NEXT: ret void
+    match x {
+        Continue(x) => Continue(x),
+        Break(x) => Break(x),
+    }
+}
+
+// CHECK-LABEL: @control_flow_nop_traits_128
+#[no_mangle]
+pub fn control_flow_nop_traits_128(x: ControlFlow<i128, u128>) -> ControlFlow<i128, u128> {
+    // CHECK: start:
+    // CHECK-NEXT: getelementptr inbounds {{(nuw )?}}i8
+    // CHECK-NEXT: store i128
+    // CHECK-NEXT: store i128
+    // CHECK-NEXT: ret void
+    try { x? }
+}
+
+// CHECK-LABEL: @result_nop_match_ptr
+#[no_mangle]
+pub fn result_nop_match_ptr(x: Result<usize, Box<()>>) -> Result<usize, Box<()>> {
+    // CHECK: start:
+    // CHECK-NEXT: insertvalue { i{{[0-9]+}}, ptr }
+    // CHECK-NEXT: insertvalue { i{{[0-9]+}}, ptr }
+    // CHECK-NEXT: ret
+    match x {
+        Ok(x) => Ok(x),
+        Err(x) => Err(x),
+    }
+}
+
+// CHECK-LABEL: @result_nop_traits_ptr
+#[no_mangle]
+pub fn result_nop_traits_ptr(x: Result<u64, NonNull<()>>) -> Result<u64, NonNull<()>> {
+    // CHECK: start:
+    // CHECK-NEXT: insertvalue { i{{[0-9]+}}, ptr }
+    // CHECK-NEXT: insertvalue { i{{[0-9]+}}, ptr }
+    // CHECK-NEXT: ret
+    try { x? }
+}
diff --git a/tests/codegen-llvm/tune-cpu-on-functions.rs b/tests/codegen-llvm/tune-cpu-on-functions.rs
new file mode 100644
index 00000000000..f50245b797f
--- /dev/null
+++ b/tests/codegen-llvm/tune-cpu-on-functions.rs
@@ -0,0 +1,21 @@
+// This test makes sure that functions get annotated with the proper
+// "tune-cpu" attribute in LLVM.
+
+//@ no-prefer-dynamic
+//
+//@ compile-flags: -C no-prepopulate-passes -C panic=abort -C linker-plugin-lto -Cpasses=name-anon-globals -Z tune-cpu=generic -Copt-level=0
+
+#![crate_type = "staticlib"]
+
+// CHECK-LABEL: define {{.*}} @exported() {{.*}} #0
+#[no_mangle]
+pub extern "C" fn exported() {
+    not_exported();
+}
+
+// CHECK-LABEL: ; tune_cpu_on_functions::not_exported
+// CHECK-NEXT: ; Function Attrs:
+// CHECK-NEXT: define {{.*}}() {{.*}} #0
+fn not_exported() {}
+
+// CHECK: attributes #0 = {{.*}} "tune-cpu"="{{.*}}"
diff --git a/tests/codegen-llvm/tuple-layout-opt.rs b/tests/codegen-llvm/tuple-layout-opt.rs
new file mode 100644
index 00000000000..5b2f65e7aa7
--- /dev/null
+++ b/tests/codegen-llvm/tuple-layout-opt.rs
@@ -0,0 +1,57 @@
+// 32-bit systems will return 128bit values using a return area pointer.
+//@ revisions: bit32 bit64
+//@[bit32] only-32bit
+//@[bit64] only-64bit
+//@ compile-flags: -C no-prepopulate-passes -Copt-level=0
+
+// Test that tuples get optimized layout, in particular with a ZST in the last field (#63244)
+
+#![crate_type = "lib"]
+
+type ScalarZstLast = (u128, ());
+// bit32: define {{(dso_local )?}}void @test_ScalarZstLast({{.*}} sret([16 x i8]) {{.*}}, i128 %_1)
+// bit64: define {{(dso_local )?}}i128 @test_ScalarZstLast(i128 %_1)
+#[no_mangle]
+pub fn test_ScalarZstLast(_: ScalarZstLast) -> ScalarZstLast {
+    loop {}
+}
+
+type ScalarZstFirst = ((), u128);
+// bit32: define {{(dso_local )?}}void @test_ScalarZstFirst({{.*}} sret([16 x i8]) {{.*}}, i128 %_1)
+// bit64: define {{(dso_local )?}}i128 @test_ScalarZstFirst(i128 %_1)
+#[no_mangle]
+pub fn test_ScalarZstFirst(_: ScalarZstFirst) -> ScalarZstFirst {
+    loop {}
+}
+
+type ScalarPairZstLast = (u8, u128, ());
+// CHECK: define {{(dso_local )?}}void @test_ScalarPairZstLast(ptr sret({{[^,]*}})
+// CHECK-SAME: %_0, i128 %_1.0, i8 %_1.1)
+#[no_mangle]
+pub fn test_ScalarPairZstLast(_: ScalarPairZstLast) -> ScalarPairZstLast {
+    loop {}
+}
+
+type ScalarPairZstFirst = ((), u8, u128);
+// CHECK: define {{(dso_local )?}}void @test_ScalarPairZstFirst(ptr sret({{[^,]*}})
+// CHECK-SAME: %_0, i8 %_1.0, i128 %_1.1)
+#[no_mangle]
+pub fn test_ScalarPairZstFirst(_: ScalarPairZstFirst) -> ScalarPairZstFirst {
+    loop {}
+}
+
+type ScalarPairLotsOfZsts = ((), u8, (), u128, ());
+// CHECK: define {{(dso_local )?}}void @test_ScalarPairLotsOfZsts(ptr sret({{[^,]*}})
+// CHECK-SAME: %_0, i128 %_1.0, i8 %_1.1)
+#[no_mangle]
+pub fn test_ScalarPairLotsOfZsts(_: ScalarPairLotsOfZsts) -> ScalarPairLotsOfZsts {
+    loop {}
+}
+
+type ScalarPairLottaNesting = (((), ((), u8, (), u128, ())), ());
+// CHECK: define {{(dso_local )?}}void @test_ScalarPairLottaNesting(ptr sret({{[^,]*}})
+// CHECK-SAME: %_0, i128 %_1.0, i8 %_1.1)
+#[no_mangle]
+pub fn test_ScalarPairLottaNesting(_: ScalarPairLottaNesting) -> ScalarPairLottaNesting {
+    loop {}
+}
diff --git a/tests/codegen-llvm/ub-checks.rs b/tests/codegen-llvm/ub-checks.rs
new file mode 100644
index 00000000000..67f5bff08d5
--- /dev/null
+++ b/tests/codegen-llvm/ub-checks.rs
@@ -0,0 +1,28 @@
+// With -Zub-checks=yes (enabled by default by -Cdebug-assertions=yes) we will produce a runtime
+// check that the index to slice::get_unchecked is in-bounds of the slice. That is tested for by
+// tests/ui/precondition-checks/out-of-bounds-get-unchecked.rs
+//
+// This test ensures that such a runtime check is *not* emitted when debug-assertions are enabled,
+// but ub-checks are explicitly disabled.
+
+//@ revisions: DEBUG NOCHECKS
+//@ [DEBUG] compile-flags:
+//@ [NOCHECKS] compile-flags: -Zub-checks=no
+//@ compile-flags: -Copt-level=3 -Cdebug-assertions=yes
+
+#![crate_type = "lib"]
+
+use std::ops::Range;
+
+// CHECK-LABEL: @slice_get_unchecked(
+#[no_mangle]
+pub unsafe fn slice_get_unchecked(x: &[i32], i: usize) -> &i32 {
+    //    CHECK: icmp ult
+    // NOCHECKS: tail call void @llvm.assume
+    //    DEBUG: br i1
+    //    DEBUG: call core::panicking::panic_nounwind
+    //    DEBUG: unreachable
+    //    CHECK: getelementptr inbounds
+    //    CHECK: ret ptr
+    x.get_unchecked(i)
+}
diff --git a/tests/codegen-llvm/unchecked-float-casts.rs b/tests/codegen-llvm/unchecked-float-casts.rs
new file mode 100644
index 00000000000..d1869abc87b
--- /dev/null
+++ b/tests/codegen-llvm/unchecked-float-casts.rs
@@ -0,0 +1,36 @@
+// This file tests that we don't generate any code for saturation when using the
+// unchecked intrinsics.
+
+//@ compile-flags: -C opt-level=3
+//@ ignore-wasm32 the wasm target is tested in `wasm_casts_*`
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @f32_to_u32
+#[no_mangle]
+pub fn f32_to_u32(x: f32) -> u32 {
+    // CHECK: fptoui
+    // CHECK-NOT: fcmp
+    // CHECK-NOT: icmp
+    // CHECK-NOT: select
+    unsafe { x.to_int_unchecked() }
+}
+
+// CHECK-LABEL: @f32_to_i32
+#[no_mangle]
+pub fn f32_to_i32(x: f32) -> i32 {
+    // CHECK: fptosi
+    // CHECK-NOT: fcmp
+    // CHECK-NOT: icmp
+    // CHECK-NOT: select
+    unsafe { x.to_int_unchecked() }
+}
+
+#[no_mangle]
+pub fn f64_to_u16(x: f64) -> u16 {
+    // CHECK: fptoui
+    // CHECK-NOT: fcmp
+    // CHECK-NOT: icmp
+    // CHECK-NOT: select
+    unsafe { x.to_int_unchecked() }
+}
diff --git a/tests/codegen-llvm/unchecked_shifts.rs b/tests/codegen-llvm/unchecked_shifts.rs
new file mode 100644
index 00000000000..3f533718a2d
--- /dev/null
+++ b/tests/codegen-llvm/unchecked_shifts.rs
@@ -0,0 +1,100 @@
+//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes
+
+// This runs mir-opts to inline the standard library call, but doesn't run LLVM
+// optimizations so it doesn't need to worry about them adding more flags.
+
+#![crate_type = "lib"]
+#![feature(unchecked_shifts)]
+#![feature(core_intrinsics)]
+
+// CHECK-LABEL: @unchecked_shl_unsigned_same
+#[no_mangle]
+pub unsafe fn unchecked_shl_unsigned_same(a: u32, b: u32) -> u32 {
+    // CHECK-NOT: assume
+    // CHECK-NOT: and i32
+    // CHECK: shl i32 %a, %b
+    // CHECK-NOT: and i32
+    a.unchecked_shl(b)
+}
+
+// CHECK-LABEL: @unchecked_shl_unsigned_smaller
+#[no_mangle]
+pub unsafe fn unchecked_shl_unsigned_smaller(a: u16, b: u32) -> u16 {
+    // CHECK-NOT: assume
+    // CHECK: %[[TRUNC:.+]] = trunc nuw i32 %b to i16
+    // CHECK: shl i16 %a, %[[TRUNC]]
+    a.unchecked_shl(b)
+}
+
+// CHECK-LABEL: @unchecked_shl_unsigned_bigger
+#[no_mangle]
+pub unsafe fn unchecked_shl_unsigned_bigger(a: u64, b: u32) -> u64 {
+    // CHECK-NOT: assume
+    // CHECK: %[[EXT:.+]] = zext i32 %b to i64
+    // CHECK: shl i64 %a, %[[EXT]]
+    a.unchecked_shl(b)
+}
+
+// CHECK-LABEL: @unchecked_shr_signed_same
+#[no_mangle]
+pub unsafe fn unchecked_shr_signed_same(a: i32, b: u32) -> i32 {
+    // CHECK-NOT: assume
+    // CHECK-NOT: and i32
+    // CHECK: ashr i32 %a, %b
+    // CHECK-NOT: and i32
+    a.unchecked_shr(b)
+}
+
+// CHECK-LABEL: @unchecked_shr_signed_smaller
+#[no_mangle]
+pub unsafe fn unchecked_shr_signed_smaller(a: i16, b: u32) -> i16 {
+    // CHECK-NOT: assume
+    // CHECK: %[[TRUNC:.+]] = trunc nuw i32 %b to i16
+    // CHECK: ashr i16 %a, %[[TRUNC]]
+    a.unchecked_shr(b)
+}
+
+// CHECK-LABEL: @unchecked_shr_signed_bigger
+#[no_mangle]
+pub unsafe fn unchecked_shr_signed_bigger(a: i64, b: u32) -> i64 {
+    // CHECK-NOT: assume
+    // CHECK: %[[EXT:.+]] = zext i32 %b to i64
+    // CHECK: ashr i64 %a, %[[EXT]]
+    a.unchecked_shr(b)
+}
+
+// CHECK-LABEL: @unchecked_shr_u128_i8
+#[no_mangle]
+pub unsafe fn unchecked_shr_u128_i8(a: u128, b: i8) -> u128 {
+    // CHECK-NOT: assume
+    // CHECK: %[[EXT:.+]] = zext i8 %b to i128
+    // CHECK: lshr i128 %a, %[[EXT]]
+    std::intrinsics::unchecked_shr(a, b)
+}
+
+// CHECK-LABEL: @unchecked_shl_i128_u8
+#[no_mangle]
+pub unsafe fn unchecked_shl_i128_u8(a: i128, b: u8) -> i128 {
+    // CHECK-NOT: assume
+    // CHECK: %[[EXT:.+]] = zext i8 %b to i128
+    // CHECK: shl i128 %a, %[[EXT]]
+    std::intrinsics::unchecked_shl(a, b)
+}
+
+// CHECK-LABEL: @unchecked_shl_u8_i128
+#[no_mangle]
+pub unsafe fn unchecked_shl_u8_i128(a: u8, b: i128) -> u8 {
+    // CHECK-NOT: assume
+    // CHECK: %[[TRUNC:.+]] = trunc nuw i128 %b to i8
+    // CHECK: shl i8 %a, %[[TRUNC]]
+    std::intrinsics::unchecked_shl(a, b)
+}
+
+// CHECK-LABEL: @unchecked_shr_i8_u128
+#[no_mangle]
+pub unsafe fn unchecked_shr_i8_u128(a: i8, b: u128) -> i8 {
+    // CHECK-NOT: assume
+    // CHECK: %[[TRUNC:.+]] = trunc nuw i128 %b to i8
+    // CHECK: ashr i8 %a, %[[TRUNC]]
+    std::intrinsics::unchecked_shr(a, b)
+}
diff --git a/tests/codegen-llvm/uninhabited-transparent-return-abi.rs b/tests/codegen-llvm/uninhabited-transparent-return-abi.rs
new file mode 100644
index 00000000000..face1577c3f
--- /dev/null
+++ b/tests/codegen-llvm/uninhabited-transparent-return-abi.rs
@@ -0,0 +1,44 @@
+//@ compile-flags: -Copt-level=3
+
+// See https://github.com/rust-lang/rust/issues/135802
+
+#![crate_type = "lib"]
+
+enum Void {}
+
+// Should be ABI-compatible with T, but wasn't prior to the PR adding this test.
+#[repr(transparent)]
+struct NoReturn<T>(T, Void);
+
+// Returned by invisible reference (in most ABIs)
+#[allow(dead_code)]
+struct Large(u64, u64, u64);
+
+extern "Rust" {
+    fn opaque() -> NoReturn<Large>;
+    fn opaque_with_arg(rsi: u32) -> NoReturn<Large>;
+}
+
+// CHECK-LABEL: @test_uninhabited_ret_by_ref
+#[no_mangle]
+pub fn test_uninhabited_ret_by_ref() {
+    // CHECK: %_1 = alloca [24 x i8], align {{8|4}}
+    // CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 24, ptr nonnull %_1)
+    // CHECK-NEXT: call void @opaque({{.*}} sret([24 x i8]) {{.*}} %_1) #2
+    // CHECK-NEXT: unreachable
+    unsafe {
+        opaque();
+    }
+}
+
+// CHECK-LABEL: @test_uninhabited_ret_by_ref_with_arg
+#[no_mangle]
+pub fn test_uninhabited_ret_by_ref_with_arg(rsi: u32) {
+    // CHECK: %_2 = alloca [24 x i8], align {{8|4}}
+    // CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 24, ptr nonnull %_2)
+    // CHECK-NEXT: call void @opaque_with_arg({{.*}} sret([24 x i8]) {{.*}} %_2, i32 noundef %rsi) #2
+    // CHECK-NEXT: unreachable
+    unsafe {
+        opaque_with_arg(rsi);
+    }
+}
diff --git a/tests/codegen-llvm/uninit-consts.rs b/tests/codegen-llvm/uninit-consts.rs
new file mode 100644
index 00000000000..bde71a35c47
--- /dev/null
+++ b/tests/codegen-llvm/uninit-consts.rs
@@ -0,0 +1,54 @@
+//@ compile-flags: -C no-prepopulate-passes
+
+// Check that we use undef (and not zero) for uninitialized bytes in constants.
+
+#![crate_type = "lib"]
+
+use std::mem::MaybeUninit;
+
+pub struct PartiallyUninit {
+    x: u32,
+    y: MaybeUninit<[u8; 10]>,
+}
+
+// CHECK: [[FULLY_UNINIT:@.*]] = private unnamed_addr constant [10 x i8] undef
+
+// CHECK: [[PARTIALLY_UNINIT:@.*]] = private unnamed_addr constant <{ [4 x i8], [12 x i8] }> <{ [4 x i8] c"{{\\EF\\BE\\AD\\DE|\\DE\\AD\\BE\\EF}}", [12 x i8] undef }>, align 4
+
+// This shouldn't contain undef, since it contains more chunks
+// than the default value of uninit_const_chunk_threshold.
+// CHECK: [[UNINIT_PADDING_HUGE:@.*]] = private unnamed_addr constant [32768 x i8] c"{{.+}}", align 4
+
+// CHECK: [[FULLY_UNINIT_HUGE:@.*]] = private unnamed_addr constant [16384 x i8] undef
+
+// CHECK-LABEL: @fully_uninit
+#[no_mangle]
+pub const fn fully_uninit() -> MaybeUninit<[u8; 10]> {
+    const M: MaybeUninit<[u8; 10]> = MaybeUninit::uninit();
+    // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 1 %_0, ptr align 1 {{.*}}[[FULLY_UNINIT]]{{.*}}, i{{(32|64)}} 10, i1 false)
+    M
+}
+
+// CHECK-LABEL: @partially_uninit
+#[no_mangle]
+pub const fn partially_uninit() -> PartiallyUninit {
+    const X: PartiallyUninit = PartiallyUninit { x: 0xdeadbeef, y: MaybeUninit::uninit() };
+    // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 4 %_0, ptr align 4 {{.*}}[[PARTIALLY_UNINIT]]{{.*}}, i{{(32|64)}} 16, i1 false)
+    X
+}
+
+// CHECK-LABEL: @uninit_padding_huge
+#[no_mangle]
+pub const fn uninit_padding_huge() -> [(u32, u8); 4096] {
+    const X: [(u32, u8); 4096] = [(123, 45); 4096];
+    // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 4 %_0, ptr align 4 {{.*}}[[UNINIT_PADDING_HUGE]]{{.*}}, i{{(32|64)}} 32768, i1 false)
+    X
+}
+
+// CHECK-LABEL: @fully_uninit_huge
+#[no_mangle]
+pub const fn fully_uninit_huge() -> MaybeUninit<[u32; 4096]> {
+    const F: MaybeUninit<[u32; 4096]> = MaybeUninit::uninit();
+    // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 4 %_0, ptr align 4 {{.*}}[[FULLY_UNINIT_HUGE]]{{.*}}, i{{(32|64)}} 16384, i1 false)
+    F
+}
diff --git a/tests/codegen-llvm/uninit-repeat-in-aggregate.rs b/tests/codegen-llvm/uninit-repeat-in-aggregate.rs
new file mode 100644
index 00000000000..0fa2eb7d56c
--- /dev/null
+++ b/tests/codegen-llvm/uninit-repeat-in-aggregate.rs
@@ -0,0 +1,21 @@
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+
+use std::mem::MaybeUninit;
+
+// We need to make sure len is at offset 0, otherwise codegen needs an extra instruction
+#[repr(C)]
+pub struct SmallVec<T> {
+    pub len: u64,
+    pub arr: [MaybeUninit<T>; 24],
+}
+
+// CHECK-LABEL: @uninit_arr_via_const
+#[no_mangle]
+pub fn uninit_arr_via_const() -> SmallVec<String> {
+    // CHECK-NEXT: start:
+    // CHECK-NEXT: store i64 0,
+    // CHECK-NEXT: ret
+    SmallVec { len: 0, arr: [const { MaybeUninit::uninit() }; 24] }
+}
diff --git a/tests/codegen-llvm/union-abi.rs b/tests/codegen-llvm/union-abi.rs
new file mode 100644
index 00000000000..28acc4de2f3
--- /dev/null
+++ b/tests/codegen-llvm/union-abi.rs
@@ -0,0 +1,145 @@
+//@ ignore-emscripten vectors passed directly
+//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes
+// 32-bit x86 returns `f32` differently to avoid the x87 stack.
+// 32-bit systems will return 128bit values using a return area pointer.
+//@ revisions: x86-sse x86-nosse bit32 bit64
+//@[x86-sse] only-x86
+//@[x86-sse] only-rustc_abi-x86-sse2
+//@[x86-nosse] only-x86
+//@[x86-nosse] ignore-rustc_abi-x86-sse2
+//@[bit32] ignore-x86
+//@[bit32] only-32bit
+//@[bit64] ignore-x86
+//@[bit64] only-64bit
+
+// This test that using union forward the abi of the inner type, as
+// discussed in #54668
+
+#![crate_type = "lib"]
+#![feature(repr_simd)]
+
+#[derive(Copy, Clone)]
+pub enum Unhab {}
+
+#[repr(simd)]
+#[derive(Copy, Clone)]
+pub struct i64x4([i64; 4]);
+
+#[derive(Copy, Clone)]
+pub union UnionI64x4 {
+    a: (),
+    b: i64x4,
+}
+
+// CHECK: define {{(dso_local )?}}void @test_UnionI64x4(ptr {{.*}} %_1)
+#[no_mangle]
+pub fn test_UnionI64x4(_: UnionI64x4) {
+    loop {}
+}
+
+pub union UnionI64x4_ {
+    a: i64x4,
+    b: (),
+    c: i64x4,
+    d: Unhab,
+    e: ((), ()),
+    f: UnionI64x4,
+}
+
+// CHECK: define {{(dso_local )?}}void @test_UnionI64x4_(ptr {{.*}} %_1)
+#[no_mangle]
+pub fn test_UnionI64x4_(_: UnionI64x4_) {
+    loop {}
+}
+
+pub union UnionI64x4I64 {
+    a: i64x4,
+    b: i64,
+}
+
+// CHECK: define {{(dso_local )?}}void @test_UnionI64x4I64(ptr {{.*}} %_1)
+#[no_mangle]
+pub fn test_UnionI64x4I64(_: UnionI64x4I64) {
+    loop {}
+}
+
+pub union UnionI64x4Tuple {
+    a: i64x4,
+    b: (i64, i64, i64, i64),
+}
+
+// CHECK: define {{(dso_local )?}}void @test_UnionI64x4Tuple(ptr {{.*}} %_1)
+#[no_mangle]
+pub fn test_UnionI64x4Tuple(_: UnionI64x4Tuple) {
+    loop {}
+}
+
+pub union UnionF32 {
+    a: f32,
+}
+
+// x86-sse: define {{(dso_local )?}}<4 x i8> @test_UnionF32(float %_1)
+// x86-nosse: define {{(dso_local )?}}i32 @test_UnionF32(float %_1)
+// bit32: define {{(dso_local )?}}float @test_UnionF32(float %_1)
+// bit64: define {{(dso_local )?}}float @test_UnionF32(float %_1)
+#[no_mangle]
+pub fn test_UnionF32(_: UnionF32) -> UnionF32 {
+    loop {}
+}
+
+pub union UnionF32F32 {
+    a: f32,
+    b: f32,
+}
+
+// x86-sse: define {{(dso_local )?}}<4 x i8> @test_UnionF32F32(float %_1)
+// x86-nosse: define {{(dso_local )?}}i32 @test_UnionF32F32(float %_1)
+// bit32: define {{(dso_local )?}}float @test_UnionF32F32(float %_1)
+// bit64: define {{(dso_local )?}}float @test_UnionF32F32(float %_1)
+#[no_mangle]
+pub fn test_UnionF32F32(_: UnionF32F32) -> UnionF32F32 {
+    loop {}
+}
+
+pub union UnionF32U32 {
+    a: f32,
+    b: u32,
+}
+
+// CHECK: define {{(dso_local )?}}i32 @test_UnionF32U32(i32{{( %0)?}})
+#[no_mangle]
+pub fn test_UnionF32U32(_: UnionF32U32) -> UnionF32U32 {
+    loop {}
+}
+
+pub union UnionU128 {
+    a: u128,
+}
+// x86-sse: define {{(dso_local )?}}void @test_UnionU128({{.*}}sret([16 x i8]){{.*}}, i128 %_1)
+// x86-nosse: define {{(dso_local )?}}void @test_UnionU128({{.*}}sret([16 x i8]){{.*}}, i128 %_1)
+// bit32: define {{(dso_local )?}}void @test_UnionU128({{.*}}sret([16 x i8]){{.*}}, i128 %_1)
+// bit64: define {{(dso_local )?}}i128 @test_UnionU128(i128 %_1)
+#[no_mangle]
+pub fn test_UnionU128(_: UnionU128) -> UnionU128 {
+    loop {}
+}
+
+#[repr(C)]
+pub union CUnionU128 {
+    a: u128,
+}
+// CHECK: define {{(dso_local )?}}void @test_CUnionU128(ptr {{.*}} %_1)
+#[no_mangle]
+pub fn test_CUnionU128(_: CUnionU128) {
+    loop {}
+}
+
+pub union UnionBool {
+    b: bool,
+}
+// CHECK: define {{(dso_local )?}}noundef zeroext i1 @test_UnionBool(i8{{.*}} %b)
+#[no_mangle]
+pub fn test_UnionBool(b: UnionBool) -> bool {
+    unsafe { b.b }
+}
+// CHECK: %_0 = trunc{{( nuw)?}} i8 %b to i1
diff --git a/tests/codegen-llvm/union-aggregate.rs b/tests/codegen-llvm/union-aggregate.rs
new file mode 100644
index 00000000000..aac66c5dcdd
--- /dev/null
+++ b/tests/codegen-llvm/union-aggregate.rs
@@ -0,0 +1,108 @@
+//@ compile-flags: -Copt-level=0 -Cno-prepopulate-passes
+//@ min-llvm-version: 19
+//@ only-64bit
+
+#![crate_type = "lib"]
+#![feature(transparent_unions)]
+#![feature(repr_simd)]
+
+#[repr(transparent)]
+union MU<T: Copy> {
+    uninit: (),
+    value: T,
+}
+
+use std::cmp::Ordering;
+use std::num::NonZero;
+use std::ptr::NonNull;
+
+#[no_mangle]
+fn make_mu_bool(x: bool) -> MU<bool> {
+    // CHECK-LABEL: i8 @make_mu_bool(i1 zeroext %x)
+    // CHECK-NEXT: start:
+    // CHECK-NEXT: %[[WIDER:.+]] = zext i1 %x to i8
+    // CHECK-NEXT: ret i8 %[[WIDER]]
+    MU { value: x }
+}
+
+#[no_mangle]
+fn make_mu_bool_uninit() -> MU<bool> {
+    // CHECK-LABEL: i8 @make_mu_bool_uninit()
+    // CHECK-NEXT: start:
+    // CHECK-NEXT: ret i8 undef
+    MU { uninit: () }
+}
+
+#[no_mangle]
+fn make_mu_ref(x: &u16) -> MU<&u16> {
+    // CHECK-LABEL: ptr @make_mu_ref(ptr align 2 %x)
+    // CHECK-NEXT: start:
+    // CHECK-NEXT: ret ptr %x
+    MU { value: x }
+}
+
+#[no_mangle]
+fn make_mu_ref_uninit<'a>() -> MU<&'a u16> {
+    // CHECK-LABEL: ptr @make_mu_ref_uninit()
+    // CHECK-NEXT: start:
+    // CHECK-NEXT: ret ptr undef
+    MU { uninit: () }
+}
+
+#[no_mangle]
+fn make_mu_str(x: &str) -> MU<&str> {
+    // CHECK-LABEL: { ptr, i64 } @make_mu_str(ptr align 1 %x.0, i64 %x.1)
+    // CHECK-NEXT: start:
+    // CHECK-NEXT: %0 = insertvalue { ptr, i64 } poison, ptr %x.0, 0
+    // CHECK-NEXT: %1 = insertvalue { ptr, i64 } %0, i64 %x.1, 1
+    // CHECK-NEXT: ret { ptr, i64 } %1
+    MU { value: x }
+}
+
+#[no_mangle]
+fn make_mu_str_uninit<'a>() -> MU<&'a str> {
+    // CHECK-LABEL: { ptr, i64 } @make_mu_str_uninit()
+    // CHECK-NEXT: start:
+    // CHECK-NEXT: ret { ptr, i64 } undef
+    MU { uninit: () }
+}
+
+#[no_mangle]
+fn make_mu_pair(x: (u8, u32)) -> MU<(u8, u32)> {
+    // CHECK-LABEL: { i8, i32 } @make_mu_pair(i8 %x.0, i32 %x.1)
+    // CHECK-NEXT: start:
+    // CHECK-NEXT: %0 = insertvalue { i8, i32 } poison, i8 %x.0, 0
+    // CHECK-NEXT: %1 = insertvalue { i8, i32 } %0, i32 %x.1, 1
+    // CHECK-NEXT: ret { i8, i32 } %1
+    MU { value: x }
+}
+
+#[no_mangle]
+fn make_mu_pair_uninit() -> MU<(u8, u32)> {
+    // CHECK-LABEL: { i8, i32 } @make_mu_pair_uninit()
+    // CHECK-NEXT: start:
+    // CHECK-NEXT: ret { i8, i32 } undef
+    MU { uninit: () }
+}
+
+#[repr(simd)]
+#[derive(Copy, Clone)]
+struct I32X32([i32; 32]);
+
+#[no_mangle]
+fn make_mu_simd(x: I32X32) -> MU<I32X32> {
+    // CHECK-LABEL: void @make_mu_simd(ptr{{.+}}%_0, ptr{{.+}}%x)
+    // CHECK-NEXT: start:
+    // CHECK-NEXT: %[[TEMP:.+]] = load <32 x i32>, ptr %x,
+    // CHECK-NEXT: store <32 x i32> %[[TEMP]], ptr %_0,
+    // CHECK-NEXT: ret void
+    MU { value: x }
+}
+
+#[no_mangle]
+fn make_mu_simd_uninit() -> MU<I32X32> {
+    // CHECK-LABEL: void @make_mu_simd_uninit(ptr{{.+}}%_0)
+    // CHECK-NEXT: start:
+    // CHECK-NEXT: ret void
+    MU { uninit: () }
+}
diff --git a/tests/codegen-llvm/unwind-abis/aapcs-unwind-abi.rs b/tests/codegen-llvm/unwind-abis/aapcs-unwind-abi.rs
new file mode 100644
index 00000000000..ecace722e0d
--- /dev/null
+++ b/tests/codegen-llvm/unwind-abis/aapcs-unwind-abi.rs
@@ -0,0 +1,36 @@
+//@ needs-llvm-components: arm
+//@ compile-flags: --target=armv7-unknown-linux-gnueabihf --crate-type=rlib -Cno-prepopulate-passes
+#![no_core]
+#![feature(no_core, lang_items)]
+
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
+#[lang = "sized"]
+pub trait Sized: MetaSized {}
+
+// Test that `nounwind` attributes are correctly applied to exported `aapcs` and
+// `aapcs-unwind` extern functions. `aapcs-unwind` functions MUST NOT have this attribute. We
+// disable optimizations above to prevent LLVM from inferring the attribute.
+
+// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 {
+#[no_mangle]
+pub extern "aapcs" fn rust_item_that_cannot_unwind() {}
+
+// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 {
+#[no_mangle]
+pub extern "aapcs-unwind" fn rust_item_that_can_unwind() {}
+
+// Now, make some assertions that the LLVM attributes for these functions are correct.  First, make
+// sure that the first item is correctly marked with the `nounwind` attribute:
+//
+// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} }
+//
+// Next, let's assert that the second item, which CAN unwind, does not have this attribute.
+//
+// CHECK: attributes #1 = {
+// CHECK-NOT: nounwind
+// CHECK: }
diff --git a/tests/codegen-llvm/unwind-abis/c-unwind-abi-panic-abort.rs b/tests/codegen-llvm/unwind-abis/c-unwind-abi-panic-abort.rs
new file mode 100644
index 00000000000..8d2745ba2f7
--- /dev/null
+++ b/tests/codegen-llvm/unwind-abis/c-unwind-abi-panic-abort.rs
@@ -0,0 +1,27 @@
+//@ compile-flags: -C panic=abort
+
+// Test that `nounwind` attributes are also applied to extern `C-unwind` Rust functions
+// when the code is compiled with `panic=abort`.
+
+#![crate_type = "lib"]
+
+// CHECK: @rust_item_that_can_unwind() unnamed_addr [[ATTR0:#[0-9]+]]
+#[no_mangle]
+pub unsafe extern "C-unwind" fn rust_item_that_can_unwind() {
+    // Handle both legacy and v0 symbol mangling.
+    // CHECK: call void @{{.*core9panicking19panic_cannot_unwind}}
+    may_unwind();
+}
+
+extern "C-unwind" {
+    // CHECK: @may_unwind() unnamed_addr [[ATTR1:#[0-9]+]]
+    fn may_unwind();
+}
+
+// Now, make sure that the LLVM attributes for this functions are correct.  First, make
+// sure that the first item is correctly marked with the `nounwind` attribute:
+//
+// CHECK: attributes [[ATTR0]] = { {{.*}}nounwind{{.*}} }
+//
+// Now, check that foreign item is correctly marked without the `nounwind` attribute.
+// CHECK-NOT: attributes [[ATTR1]] = { {{.*}}nounwind{{.*}} }
diff --git a/tests/codegen-llvm/unwind-abis/c-unwind-abi.rs b/tests/codegen-llvm/unwind-abis/c-unwind-abi.rs
new file mode 100644
index 00000000000..46c08b5fc4f
--- /dev/null
+++ b/tests/codegen-llvm/unwind-abis/c-unwind-abi.rs
@@ -0,0 +1,27 @@
+//@ compile-flags: -C opt-level=0
+//@ needs-unwind
+
+// Test that `nounwind` attributes are correctly applied to exported `C` and `C-unwind` extern
+// functions. `C-unwind` functions MUST NOT have this attribute. We disable optimizations above
+// to prevent LLVM from inferring the attribute.
+
+#![crate_type = "lib"]
+
+// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 {
+#[no_mangle]
+pub extern "C" fn rust_item_that_cannot_unwind() {}
+
+// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 {
+#[no_mangle]
+pub extern "C-unwind" fn rust_item_that_can_unwind() {}
+
+// Now, make some assertions that the LLVM attributes for these functions are correct.  First, make
+// sure that the first item is correctly marked with the `nounwind` attribute:
+//
+// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} }
+//
+// Next, let's assert that the second item, which CAN unwind, does not have this attribute.
+//
+// CHECK: attributes #1 = {
+// CHECK-NOT: nounwind
+// CHECK: }
diff --git a/tests/codegen-llvm/unwind-abis/cdecl-unwind-abi.rs b/tests/codegen-llvm/unwind-abis/cdecl-unwind-abi.rs
new file mode 100644
index 00000000000..8e643d6ce49
--- /dev/null
+++ b/tests/codegen-llvm/unwind-abis/cdecl-unwind-abi.rs
@@ -0,0 +1,27 @@
+//@ compile-flags: -C opt-level=0
+//@ needs-unwind
+
+// Test that `nounwind` attributes are correctly applied to exported `cdecl` and
+// `cdecl-unwind` extern functions. `cdecl-unwind` functions MUST NOT have this attribute. We
+// disable optimizations above to prevent LLVM from inferring the attribute.
+
+#![crate_type = "lib"]
+
+// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 {
+#[no_mangle]
+pub extern "cdecl" fn rust_item_that_cannot_unwind() {}
+
+// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 {
+#[no_mangle]
+pub extern "cdecl-unwind" fn rust_item_that_can_unwind() {}
+
+// Now, make some assertions that the LLVM attributes for these functions are correct.  First, make
+// sure that the first item is correctly marked with the `nounwind` attribute:
+//
+// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} }
+//
+// Next, let's assert that the second item, which CAN unwind, does not have this attribute.
+//
+// CHECK: attributes #1 = {
+// CHECK-NOT: nounwind
+// CHECK: }
diff --git a/tests/codegen-llvm/unwind-abis/fastcall-unwind-abi.rs b/tests/codegen-llvm/unwind-abis/fastcall-unwind-abi.rs
new file mode 100644
index 00000000000..7df46813ed1
--- /dev/null
+++ b/tests/codegen-llvm/unwind-abis/fastcall-unwind-abi.rs
@@ -0,0 +1,36 @@
+//@ needs-llvm-components: x86
+//@ compile-flags: --target=i686-pc-windows-msvc --crate-type=rlib -Cno-prepopulate-passes
+#![no_core]
+#![feature(no_core, lang_items)]
+
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
+#[lang = "sized"]
+pub trait Sized: MetaSized {}
+
+// Test that `nounwind` attributes are correctly applied to exported `fastcall` and
+// `fastcall-unwind` extern functions. `fastcall-unwind` functions MUST NOT have this attribute. We
+// disable optimizations above to prevent LLVM from inferring the attribute.
+
+// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 {
+#[no_mangle]
+pub extern "fastcall" fn rust_item_that_cannot_unwind() {}
+
+// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 {
+#[no_mangle]
+pub extern "fastcall-unwind" fn rust_item_that_can_unwind() {}
+
+// Now, make some assertions that the LLVM attributes for these functions are correct.  First, make
+// sure that the first item is correctly marked with the `nounwind` attribute:
+//
+// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} }
+//
+// Next, let's assert that the second item, which CAN unwind, does not have this attribute.
+//
+// CHECK: attributes #1 = {
+// CHECK-NOT: nounwind
+// CHECK: }
diff --git a/tests/codegen-llvm/unwind-abis/nounwind-on-stable-panic-abort.rs b/tests/codegen-llvm/unwind-abis/nounwind-on-stable-panic-abort.rs
new file mode 100644
index 00000000000..d27cbd60437
--- /dev/null
+++ b/tests/codegen-llvm/unwind-abis/nounwind-on-stable-panic-abort.rs
@@ -0,0 +1,15 @@
+//@ compile-flags: -C opt-level=0 -Cpanic=abort
+
+#![crate_type = "lib"]
+
+// We disable optimizations to prevent LLVM from inferring the attribute.
+
+// CHECK: Function Attrs:{{.*}}nounwind
+// CHECK-NEXT: @foo
+#[no_mangle]
+pub extern "C" fn foo() {}
+
+// CHECK: Function Attrs:{{.*}}nounwind
+// CHECK-NEXT: @bar
+#[no_mangle]
+pub fn bar() {}
diff --git a/tests/codegen-llvm/unwind-abis/nounwind.rs b/tests/codegen-llvm/unwind-abis/nounwind.rs
new file mode 100644
index 00000000000..e40ed48ca73
--- /dev/null
+++ b/tests/codegen-llvm/unwind-abis/nounwind.rs
@@ -0,0 +1,16 @@
+//@ compile-flags: -C opt-level=0 -Cpanic=abort
+//@ needs-unwind
+
+#![crate_type = "lib"]
+
+// We disable optimizations to prevent LLVM from inferring the attribute.
+
+// CHECK: Function Attrs:{{.*}}nounwind
+// CHECK-NEXT: @foo
+#[no_mangle]
+pub extern "C" fn foo() {}
+
+// CHECK: Function Attrs:{{.*}}nounwind
+// CHECK-NEXT: @bar
+#[no_mangle]
+pub fn bar() {}
diff --git a/tests/codegen-llvm/unwind-abis/stdcall-unwind-abi.rs b/tests/codegen-llvm/unwind-abis/stdcall-unwind-abi.rs
new file mode 100644
index 00000000000..cc06ee12549
--- /dev/null
+++ b/tests/codegen-llvm/unwind-abis/stdcall-unwind-abi.rs
@@ -0,0 +1,36 @@
+//@ needs-llvm-components: x86
+//@ compile-flags: --target=i686-pc-windows-msvc --crate-type=rlib -Cno-prepopulate-passes
+#![no_core]
+#![feature(no_core, lang_items)]
+
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
+#[lang = "sized"]
+pub trait Sized: MetaSized {}
+
+// Test that `nounwind` attributes are correctly applied to exported `stdcall` and `stdcall-unwind`
+// extern functions. `stdcall-unwind` functions MUST NOT have this attribute. We disable
+// optimizations above to prevent LLVM from inferring the attribute.
+
+// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 {
+#[no_mangle]
+pub extern "stdcall" fn rust_item_that_cannot_unwind() {}
+
+// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 {
+#[no_mangle]
+pub extern "stdcall-unwind" fn rust_item_that_can_unwind() {}
+
+// Now, make some assertions that the LLVM attributes for these functions are correct.  First, make
+// sure that the first item is correctly marked with the `nounwind` attribute:
+//
+// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} }
+//
+// Next, let's assert that the second item, which CAN unwind, does not have this attribute.
+//
+// CHECK: attributes #1 = {
+// CHECK-NOT: nounwind
+// CHECK: }
diff --git a/tests/codegen-llvm/unwind-abis/system-unwind-abi.rs b/tests/codegen-llvm/unwind-abis/system-unwind-abi.rs
new file mode 100644
index 00000000000..5f910248346
--- /dev/null
+++ b/tests/codegen-llvm/unwind-abis/system-unwind-abi.rs
@@ -0,0 +1,27 @@
+//@ compile-flags: -C opt-level=0
+//@ needs-unwind
+
+// Test that `nounwind` attributes are correctly applied to exported `system` and `system-unwind`
+// extern functions. `system-unwind` functions MUST NOT have this attribute. We disable
+// optimizations above to prevent LLVM from inferring the attribute.
+
+#![crate_type = "lib"]
+
+// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 {
+#[no_mangle]
+pub extern "system" fn rust_item_that_cannot_unwind() {}
+
+// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 {
+#[no_mangle]
+pub extern "system-unwind" fn rust_item_that_can_unwind() {}
+
+// Now, make some assertions that the LLVM attributes for these functions are correct.  First, make
+// sure that the first item is correctly marked with the `nounwind` attribute:
+//
+// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} }
+//
+// Next, let's assert that the second item, which CAN unwind, does not have this attribute.
+//
+// CHECK: attributes #1 = {
+// CHECK-NOT: nounwind
+// CHECK: }
diff --git a/tests/codegen-llvm/unwind-abis/sysv64-unwind-abi.rs b/tests/codegen-llvm/unwind-abis/sysv64-unwind-abi.rs
new file mode 100644
index 00000000000..69bfaf80b4b
--- /dev/null
+++ b/tests/codegen-llvm/unwind-abis/sysv64-unwind-abi.rs
@@ -0,0 +1,36 @@
+//@ needs-llvm-components: x86
+//@ compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=rlib -Cno-prepopulate-passes
+#![no_core]
+#![feature(no_core, lang_items)]
+
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
+#[lang = "sized"]
+pub trait Sized: MetaSized {}
+
+// Test that `nounwind` attributes are correctly applied to exported `sysv64` and
+// `sysv64-unwind` extern functions. `sysv64-unwind` functions MUST NOT have this attribute. We
+// disable optimizations above to prevent LLVM from inferring the attribute.
+
+// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 {
+#[no_mangle]
+pub extern "sysv64" fn rust_item_that_cannot_unwind() {}
+
+// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 {
+#[no_mangle]
+pub extern "sysv64-unwind" fn rust_item_that_can_unwind() {}
+
+// Now, make some assertions that the LLVM attributes for these functions are correct.  First, make
+// sure that the first item is correctly marked with the `nounwind` attribute:
+//
+// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} }
+//
+// Next, let's assert that the second item, which CAN unwind, does not have this attribute.
+//
+// CHECK: attributes #1 = {
+// CHECK-NOT: nounwind
+// CHECK: }
diff --git a/tests/codegen-llvm/unwind-abis/thiscall-unwind-abi.rs b/tests/codegen-llvm/unwind-abis/thiscall-unwind-abi.rs
new file mode 100644
index 00000000000..05f6b8b70e1
--- /dev/null
+++ b/tests/codegen-llvm/unwind-abis/thiscall-unwind-abi.rs
@@ -0,0 +1,36 @@
+//@ needs-llvm-components: x86
+//@ compile-flags: --target=i686-pc-windows-msvc --crate-type=rlib -Cno-prepopulate-passes
+#![no_core]
+#![feature(no_core, lang_items)]
+
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
+#[lang = "sized"]
+pub trait Sized: MetaSized {}
+
+// Test that `nounwind` attributes are correctly applied to exported `thiscall` and
+// `thiscall-unwind` extern functions. `thiscall-unwind` functions MUST NOT have this attribute. We
+// disable optimizations above to prevent LLVM from inferring the attribute.
+
+// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 {
+#[no_mangle]
+pub extern "thiscall" fn rust_item_that_cannot_unwind() {}
+
+// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 {
+#[no_mangle]
+pub extern "thiscall-unwind" fn rust_item_that_can_unwind() {}
+
+// Now, make some assertions that the LLVM attributes for these functions are correct.  First, make
+// sure that the first item is correctly marked with the `nounwind` attribute:
+//
+// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} }
+//
+// Next, let's assert that the second item, which CAN unwind, does not have this attribute.
+//
+// CHECK: attributes #1 = {
+// CHECK-NOT: nounwind
+// CHECK: }
diff --git a/tests/codegen-llvm/unwind-abis/vectorcall-unwind-abi.rs b/tests/codegen-llvm/unwind-abis/vectorcall-unwind-abi.rs
new file mode 100644
index 00000000000..d001a16b32a
--- /dev/null
+++ b/tests/codegen-llvm/unwind-abis/vectorcall-unwind-abi.rs
@@ -0,0 +1,36 @@
+//@ needs-llvm-components: x86
+//@ compile-flags: --target=i686-pc-windows-msvc --crate-type=rlib -Cno-prepopulate-passes
+#![no_core]
+#![feature(no_core, lang_items, abi_vectorcall)]
+
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
+#[lang = "sized"]
+pub trait Sized: MetaSized {}
+
+// Test that `nounwind` attributes are correctly applied to exported `vectorcall` and
+// `vectorcall-unwind` extern functions. `vectorcall-unwind` functions MUST NOT have this attribute.
+// We disable optimizations above to prevent LLVM from inferring the attribute.
+
+// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 {
+#[no_mangle]
+pub extern "vectorcall" fn rust_item_that_cannot_unwind() {}
+
+// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 {
+#[no_mangle]
+pub extern "vectorcall-unwind" fn rust_item_that_can_unwind() {}
+
+// Now, make some assertions that the LLVM attributes for these functions are correct.  First, make
+// sure that the first item is correctly marked with the `nounwind` attribute:
+//
+// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} }
+//
+// Next, let's assert that the second item, which CAN unwind, does not have this attribute.
+//
+// CHECK: attributes #1 = {
+// CHECK-NOT: nounwind
+// CHECK: }
diff --git a/tests/codegen-llvm/unwind-abis/win64-unwind-abi.rs b/tests/codegen-llvm/unwind-abis/win64-unwind-abi.rs
new file mode 100644
index 00000000000..257f00b54e4
--- /dev/null
+++ b/tests/codegen-llvm/unwind-abis/win64-unwind-abi.rs
@@ -0,0 +1,36 @@
+//@ needs-llvm-components: x86
+//@ compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=rlib -Cno-prepopulate-passes
+#![no_core]
+#![feature(no_core, lang_items)]
+
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
+#[lang = "sized"]
+pub trait Sized: MetaSized {}
+
+// Test that `nounwind` attributes are correctly applied to exported `win64` and
+// `win64-unwind` extern functions. `win64-unwind` functions MUST NOT have this attribute. We
+// disable optimizations above to prevent LLVM from inferring the attribute.
+
+// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 {
+#[no_mangle]
+pub extern "win64" fn rust_item_that_cannot_unwind() {}
+
+// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 {
+#[no_mangle]
+pub extern "win64-unwind" fn rust_item_that_can_unwind() {}
+
+// Now, make some assertions that the LLVM attributes for these functions are correct.  First, make
+// sure that the first item is correctly marked with the `nounwind` attribute:
+//
+// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} }
+//
+// Next, let's assert that the second item, which CAN unwind, does not have this attribute.
+//
+// CHECK: attributes #1 = {
+// CHECK-NOT: nounwind
+// CHECK: }
diff --git a/tests/codegen-llvm/unwind-and-panic-abort.rs b/tests/codegen-llvm/unwind-and-panic-abort.rs
new file mode 100644
index 00000000000..8efa140058a
--- /dev/null
+++ b/tests/codegen-llvm/unwind-and-panic-abort.rs
@@ -0,0 +1,16 @@
+//@ compile-flags: -C panic=abort
+
+#![crate_type = "lib"]
+
+extern "C-unwind" {
+    fn bar();
+}
+
+// CHECK: Function Attrs:{{.*}}nounwind
+// CHECK-NEXT: define{{.*}}void @foo
+// Handle both legacy and v0 symbol mangling.
+// CHECK: call void @{{.*core9panicking19panic_cannot_unwind}}
+#[no_mangle]
+pub unsafe extern "C" fn foo() {
+    bar();
+}
diff --git a/tests/codegen-llvm/unwind-extern-exports.rs b/tests/codegen-llvm/unwind-extern-exports.rs
new file mode 100644
index 00000000000..e692fd1a547
--- /dev/null
+++ b/tests/codegen-llvm/unwind-extern-exports.rs
@@ -0,0 +1,15 @@
+//@ compile-flags: -C opt-level=0
+//@ needs-unwind
+
+#![crate_type = "lib"]
+
+// Make sure these all do *not* get the attribute.
+// We disable optimizations to prevent LLVM from inferring the attribute.
+// CHECK-NOT: nounwind
+
+// "C" ABI
+pub extern "C-unwind" fn foo_unwind() {}
+
+// "Rust"
+// (`extern "Rust"` could be removed as all `fn` get it implicitly; we leave it in for clarity.)
+pub fn bar() {}
diff --git a/tests/codegen-llvm/unwind-extern-imports.rs b/tests/codegen-llvm/unwind-extern-imports.rs
new file mode 100644
index 00000000000..dfae8aae64a
--- /dev/null
+++ b/tests/codegen-llvm/unwind-extern-imports.rs
@@ -0,0 +1,21 @@
+//@ compile-flags: -C no-prepopulate-passes
+//@ needs-unwind
+
+#![crate_type = "lib"]
+
+extern "C" {
+    // CHECK: Function Attrs:{{.*}}nounwind
+    // CHECK-NEXT: declare{{.*}}void @extern_fn
+    fn extern_fn();
+}
+
+extern "C-unwind" {
+    // CHECK-NOT: nounwind
+    // CHECK: declare{{.*}}void @c_unwind_extern_fn
+    fn c_unwind_extern_fn();
+}
+
+pub unsafe fn force_declare() {
+    extern_fn();
+    c_unwind_extern_fn();
+}
diff --git a/tests/codegen-llvm/unwind-landingpad-cold.rs b/tests/codegen-llvm/unwind-landingpad-cold.rs
new file mode 100644
index 00000000000..fb095e04650
--- /dev/null
+++ b/tests/codegen-llvm/unwind-landingpad-cold.rs
@@ -0,0 +1,15 @@
+//@ compile-flags: -Cno-prepopulate-passes
+//@ needs-unwind
+#![crate_type = "lib"]
+
+// This test checks that drop calls in unwind landing pads
+// get the `cold` attribute.
+
+// CHECK-LABEL: @check_cold
+// CHECK: {{(call|invoke) void .+}}drop_in_place{{.+}} [[ATTRIBUTES:#[0-9]+]]
+// CHECK: attributes [[ATTRIBUTES]] = { cold }
+#[no_mangle]
+pub fn check_cold(f: fn(), x: Box<u32>) {
+    // this may unwind
+    f();
+}
diff --git a/tests/codegen-llvm/unwind-landingpad-inline.rs b/tests/codegen-llvm/unwind-landingpad-inline.rs
new file mode 100644
index 00000000000..1cf606279e6
--- /dev/null
+++ b/tests/codegen-llvm/unwind-landingpad-inline.rs
@@ -0,0 +1,39 @@
+//@ compile-flags: -Copt-level=3
+#![crate_type = "lib"]
+
+// This test checks that we can inline drop_in_place in
+// unwind landing pads.
+
+// Without inlining, the box pointers escape via the call to drop_in_place,
+// and LLVM will not optimize out the pointer comparison.
+// With inlining, everything should be optimized out.
+// See https://github.com/rust-lang/rust/issues/46515
+// CHECK-LABEL: @check_no_escape_in_landingpad
+// CHECK: start:
+// CHECK-NEXT: ; call __rustc::__rust_no_alloc_shim_is_unstable_v2
+// CHECK-NEXT: tail call void @[[NO_ALLOC_SHIM:_R.+__rust_no_alloc_shim_is_unstable_v2]]()
+// CHECK-NEXT: ; call __rustc::__rust_no_alloc_shim_is_unstable_v2
+// CHECK-NEXT: tail call void @[[NO_ALLOC_SHIM]]()
+// CHECK-NEXT: ret void
+#[no_mangle]
+pub fn check_no_escape_in_landingpad(f: fn()) {
+    let x = &*Box::new(0);
+    let y = &*Box::new(0);
+
+    if x as *const _ == y as *const _ {
+        f();
+    }
+}
+
+// Without inlining, the compiler can't tell that
+// dropping an empty string (in a landing pad) does nothing.
+// With inlining, the landing pad should be optimized out.
+// See https://github.com/rust-lang/rust/issues/87055
+// CHECK-LABEL: @check_eliminate_noop_drop
+// CHECK: call void %g()
+// CHECK-NEXT: ret void
+#[no_mangle]
+pub fn check_eliminate_noop_drop(g: fn()) {
+    let _var = String::new();
+    g();
+}
diff --git a/tests/codegen-llvm/used_with_arg.rs b/tests/codegen-llvm/used_with_arg.rs
new file mode 100644
index 00000000000..4515cb2aed0
--- /dev/null
+++ b/tests/codegen-llvm/used_with_arg.rs
@@ -0,0 +1,10 @@
+#![crate_type = "lib"]
+#![feature(used_with_arg)]
+
+// CHECK: @llvm.used = appending global {{.*}}USED_LINKER
+#[used(linker)]
+static mut USED_LINKER: [usize; 1] = [0];
+
+// CHECK-NEXT: @llvm.compiler.used = appending global {{.*}}USED_COMPILER
+#[used(compiler)]
+static mut USED_COMPILER: [usize; 1] = [0];
diff --git a/tests/codegen-llvm/var-names.rs b/tests/codegen-llvm/var-names.rs
new file mode 100644
index 00000000000..40720e19761
--- /dev/null
+++ b/tests/codegen-llvm/var-names.rs
@@ -0,0 +1,15 @@
+//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: define{{.*}}i32 @test(i32{{.*}} %a, i32{{.*}} %b)
+#[no_mangle]
+pub fn test(a: u32, b: u32) -> u32 {
+    let c = a + b;
+    // CHECK: %c = add i32 %a, %b
+    let d = c;
+    let e = d * a;
+    // CHECK-NEXT: %e = mul i32 %c, %a
+    e
+    // CHECK-NEXT: ret i32 %e
+}
diff --git a/tests/codegen-llvm/vec-as-ptr.rs b/tests/codegen-llvm/vec-as-ptr.rs
new file mode 100644
index 00000000000..5c997802640
--- /dev/null
+++ b/tests/codegen-llvm/vec-as-ptr.rs
@@ -0,0 +1,19 @@
+//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled
+
+#![crate_type = "lib"]
+
+// Test that even though we return a *const u8 not a &[u8] or a NonNull<u8>, LLVM knows that this
+// pointer is nonnull.
+// CHECK: nonnull ptr @vec_as_ptr
+#[no_mangle]
+pub fn vec_as_ptr(v: &Vec<u8>) -> *const u8 {
+    v.as_ptr()
+}
+
+// Test that even though we return a *const u8 not a &[u8] or a NonNull<u8>, LLVM knows that this
+// pointer is nonnull.
+// CHECK: nonnull ptr @vec_as_mut_ptr
+#[no_mangle]
+pub fn vec_as_mut_ptr(v: &mut Vec<u8>) -> *mut u8 {
+    v.as_mut_ptr()
+}
diff --git a/tests/codegen-llvm/vec-calloc.rs b/tests/codegen-llvm/vec-calloc.rs
new file mode 100644
index 00000000000..d1c320ead01
--- /dev/null
+++ b/tests/codegen-llvm/vec-calloc.rs
@@ -0,0 +1,182 @@
+//@ compile-flags: -Copt-level=3 -Z merge-functions=disabled
+//@ only-x86_64
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @vec_zero_bytes
+#[no_mangle]
+pub fn vec_zero_bytes(n: usize) -> Vec<u8> {
+    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+    // CHECK-NOT: call {{.*}}reserve
+    // CHECK-NOT: call {{.*}}__rust_alloc(
+    // CHECK-NOT: call {{.*}}llvm.memset
+
+    // CHECK: call {{.*}}__rust_alloc_zeroed(
+
+    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+    // CHECK-NOT: call {{.*}}reserve
+    // CHECK-NOT: call {{.*}}__rust_alloc(
+    // CHECK-NOT: call {{.*}}llvm.memset
+
+    // CHECK: ret void
+    vec![0; n]
+}
+
+// CHECK-LABEL: @vec_one_bytes
+#[no_mangle]
+pub fn vec_one_bytes(n: usize) -> Vec<u8> {
+    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+    // CHECK-NOT: call {{.*}}reserve
+    // CHECK-NOT: call {{.*}}__rust_alloc_zeroed(
+
+    // CHECK: call {{.*}}__rust_alloc(
+    // CHECK: call {{.*}}llvm.memset
+
+    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+    // CHECK-NOT: call {{.*}}reserve
+    // CHECK-NOT: call {{.*}}__rust_alloc_zeroed(
+
+    // CHECK: ret void
+    vec![1; n]
+}
+
+// CHECK-LABEL: @vec_zero_scalar
+#[no_mangle]
+pub fn vec_zero_scalar(n: usize) -> Vec<i32> {
+    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+    // CHECK-NOT: call {{.*}}reserve
+    // CHECK-NOT: call {{.*}}__rust_alloc(
+
+    // CHECK: call {{.*}}__rust_alloc_zeroed(
+
+    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+    // CHECK-NOT: call {{.*}}reserve
+    // CHECK-NOT: call {{.*}}__rust_alloc(
+
+    // CHECK: ret void
+    vec![0; n]
+}
+
+// CHECK-LABEL: @vec_one_scalar
+#[no_mangle]
+pub fn vec_one_scalar(n: usize) -> Vec<i32> {
+    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+    // CHECK-NOT: call {{.*}}reserve
+    // CHECK-NOT: call {{.*}}__rust_alloc_zeroed(
+
+    // CHECK: call {{.*}}__rust_alloc(
+
+    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+    // CHECK-NOT: call {{.*}}reserve
+    // CHECK-NOT: call {{.*}}__rust_alloc_zeroed(
+
+    // CHECK: ret void
+    vec![1; n]
+}
+
+// CHECK-LABEL: @vec_zero_rgb48
+#[no_mangle]
+pub fn vec_zero_rgb48(n: usize) -> Vec<[u16; 3]> {
+    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+    // CHECK-NOT: call {{.*}}reserve
+    // CHECK-NOT: call {{.*}}__rust_alloc(
+
+    // CHECK: call {{.*}}__rust_alloc_zeroed(
+
+    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+    // CHECK-NOT: call {{.*}}reserve
+    // CHECK-NOT: call {{.*}}__rust_alloc(
+
+    // CHECK: ret void
+    vec![[0, 0, 0]; n]
+}
+
+// CHECK-LABEL: @vec_zero_array_16
+#[no_mangle]
+pub fn vec_zero_array_16(n: usize) -> Vec<[i64; 16]> {
+    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+    // CHECK-NOT: call {{.*}}reserve
+    // CHECK-NOT: call {{.*}}__rust_alloc(
+
+    // CHECK: call {{.*}}__rust_alloc_zeroed(
+
+    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+    // CHECK-NOT: call {{.*}}reserve
+    // CHECK-NOT: call {{.*}}__rust_alloc(
+
+    // CHECK: ret void
+    vec![[0_i64; 16]; n]
+}
+
+// CHECK-LABEL: @vec_zero_tuple
+#[no_mangle]
+pub fn vec_zero_tuple(n: usize) -> Vec<(i16, u8, char)> {
+    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+    // CHECK-NOT: call {{.*}}reserve
+    // CHECK-NOT: call {{.*}}__rust_alloc(
+
+    // CHECK: call {{.*}}__rust_alloc_zeroed(
+
+    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+    // CHECK-NOT: call {{.*}}reserve
+    // CHECK-NOT: call {{.*}}__rust_alloc(
+
+    // CHECK: ret void
+    vec![(0, 0, '\0'); n]
+}
+
+// CHECK-LABEL: @vec_non_zero_tuple
+#[no_mangle]
+pub fn vec_non_zero_tuple(n: usize) -> Vec<(i16, u8, char)> {
+    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+    // CHECK-NOT: call {{.*}}reserve
+    // CHECK-NOT: call {{.*}}__rust_alloc_zeroed(
+
+    // CHECK: call {{.*}}__rust_alloc(
+
+    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+    // CHECK-NOT: call {{.*}}reserve
+    // CHECK-NOT: call {{.*}}__rust_alloc_zeroed(
+
+    // CHECK: ret void
+    vec![(0, 0, 'A'); n]
+}
+
+// CHECK-LABEL: @vec_option_bool
+#[no_mangle]
+pub fn vec_option_bool(n: usize) -> Vec<Option<bool>> {
+    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+    // CHECK-NOT: call {{.*}}reserve
+    // CHECK-NOT: call {{.*}}__rust_alloc(
+
+    // CHECK: call {{.*}}__rust_alloc_zeroed(
+
+    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+    // CHECK-NOT: call {{.*}}reserve
+    // CHECK-NOT: call {{.*}}__rust_alloc(
+
+    // CHECK: ret void
+    vec![Some(false); n]
+}
+
+// CHECK-LABEL: @vec_option_i32
+#[no_mangle]
+pub fn vec_option_i32(n: usize) -> Vec<Option<i32>> {
+    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+    // CHECK-NOT: call {{.*}}reserve
+    // CHECK-NOT: call {{.*}}__rust_alloc(
+
+    // CHECK: call {{.*}}__rust_alloc_zeroed(
+
+    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+    // CHECK-NOT: call {{.*}}reserve
+    // CHECK-NOT: call {{.*}}__rust_alloc(
+
+    // CHECK: ret void
+    vec![None; n]
+}
+
+// Ensure that __rust_alloc_zeroed gets the right attributes for LLVM to optimize it away.
+// CHECK: declare noalias noundef ptr @{{.*}}__rust_alloc_zeroed(i64 noundef, i64 allocalign noundef) unnamed_addr [[RUST_ALLOC_ZEROED_ATTRS:#[0-9]+]]
+
+// CHECK-DAG: attributes [[RUST_ALLOC_ZEROED_ATTRS]] = { {{.*}} allockind("alloc,zeroed,aligned") allocsize(0) uwtable "alloc-family"="__rust_alloc" {{.*}} }
diff --git a/tests/codegen-llvm/vec-in-place.rs b/tests/codegen-llvm/vec-in-place.rs
new file mode 100644
index 00000000000..a5ef8653b99
--- /dev/null
+++ b/tests/codegen-llvm/vec-in-place.rs
@@ -0,0 +1,161 @@
+//@ ignore-std-debug-assertions (FIXME: checks for call detect scoped noalias metadata)
+//@ compile-flags: -Copt-level=3 -Z merge-functions=disabled
+#![crate_type = "lib"]
+
+// Ensure that trivial casts of vec elements are O(1)
+
+pub struct Wrapper<T>(T);
+
+// previously repr(C) caused the optimization to fail
+#[repr(C)]
+pub struct Foo {
+    a: u64,
+    b: u64,
+    c: u64,
+    d: u64,
+}
+
+// implementing Copy exercises the TrustedRandomAccess specialization inside the in-place
+// specialization
+#[derive(Copy, Clone)]
+pub struct Bar {
+    a: u64,
+    b: u64,
+    c: u64,
+    d: u64,
+}
+
+// this exercises the try-fold codepath
+pub struct Baz {
+    a: u64,
+    b: u64,
+    c: u64,
+    d: u64,
+}
+
+// CHECK-LABEL: @vec_iterator_cast_primitive
+#[no_mangle]
+pub fn vec_iterator_cast_primitive(vec: Vec<i8>) -> Vec<u8> {
+    // CHECK-NOT: loop
+    // CHECK-NOT: call
+    // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}})
+    // CHECK-NOT: loop
+    // CHECK-NOT: call
+    vec.into_iter().map(|e| e as u8).collect()
+}
+
+// CHECK-LABEL: @vec_iterator_cast_wrapper
+#[no_mangle]
+pub fn vec_iterator_cast_wrapper(vec: Vec<u8>) -> Vec<Wrapper<u8>> {
+    // CHECK-NOT: loop
+    // CHECK-NOT: call
+    // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}})
+    // CHECK-NOT: loop
+    // CHECK-NOT: call
+    vec.into_iter().map(|e| Wrapper(e)).collect()
+}
+
+// CHECK-LABEL: @vec_iterator_cast_signed
+#[no_mangle]
+pub fn vec_iterator_cast_signed(vec: Vec<i32>) -> Vec<u32> {
+    // CHECK-NOT: and i{{[0-9]+}} %{{.*}}, {{[0-9]+}}
+    vec.into_iter().map(|e| u32::from_ne_bytes(e.to_ne_bytes())).collect()
+}
+
+// CHECK-LABEL: @vec_iterator_cast_signed_nested
+#[no_mangle]
+pub fn vec_iterator_cast_signed_nested(vec: Vec<Vec<i32>>) -> Vec<Vec<u32>> {
+    // CHECK-NOT: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}
+    // CHECK-NOT: %{{.*}} = udiv
+    vec.into_iter()
+        .map(|e| e.into_iter().map(|e| u32::from_ne_bytes(e.to_ne_bytes())).collect())
+        .collect()
+}
+
+// CHECK-LABEL: @vec_iterator_cast_unwrap
+#[no_mangle]
+pub fn vec_iterator_cast_unwrap(vec: Vec<Wrapper<u8>>) -> Vec<u8> {
+    // CHECK-NOT: loop
+    // CHECK-NOT: call
+    // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}})
+    // CHECK-NOT: loop
+    // CHECK-NOT: call
+    vec.into_iter().map(|e| e.0).collect()
+}
+
+// CHECK-LABEL: @vec_iterator_cast_aggregate
+#[no_mangle]
+pub fn vec_iterator_cast_aggregate(vec: Vec<[u64; 4]>) -> Vec<Foo> {
+    // CHECK-NOT: loop
+    // CHECK-NOT: call
+    // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}})
+    // CHECK-NOT: loop
+    // CHECK-NOT: call
+    vec.into_iter().map(|e| unsafe { std::mem::transmute(e) }).collect()
+}
+
+// CHECK-LABEL: @vec_iterator_cast_deaggregate_tra
+#[no_mangle]
+pub fn vec_iterator_cast_deaggregate_tra(vec: Vec<Bar>) -> Vec<[u64; 4]> {
+    // CHECK-NOT: loop
+    // CHECK-NOT: call
+    // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}})
+    // CHECK-NOT: loop
+    // CHECK-NOT: call
+
+    // Safety: For the purpose of this test we assume that Bar layout matches [u64; 4].
+    // This currently is not guaranteed for repr(Rust) types, but it happens to work here and
+    // the UCG may add additional guarantees for homogenous types in the future that would make this
+    // correct.
+    vec.into_iter().map(|e| unsafe { std::mem::transmute(e) }).collect()
+}
+
+// CHECK-LABEL: @vec_iterator_cast_deaggregate_fold
+#[no_mangle]
+pub fn vec_iterator_cast_deaggregate_fold(vec: Vec<Baz>) -> Vec<[u64; 4]> {
+    // CHECK-NOT: loop
+    // CHECK-NOT: call
+    // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}})
+    // CHECK-NOT: loop
+    // CHECK-NOT: call
+
+    // Safety: For the purpose of this test we assume that Bar layout matches [u64; 4].
+    // This currently is not guaranteed for repr(Rust) types, but it happens to work here and
+    // the UCG may add additional guarantees for homogenous types in the future that would make this
+    // correct.
+    vec.into_iter().map(|e| unsafe { std::mem::transmute(e) }).collect()
+}
+
+// CHECK-LABEL: @vec_iterator_cast_unwrap_drop
+#[no_mangle]
+pub fn vec_iterator_cast_unwrap_drop(vec: Vec<Wrapper<String>>) -> Vec<String> {
+    // CHECK-NOT: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}
+    // CHECK-NOT: %{{.*}} = mul
+    // CHECK-NOT: %{{.*}} = udiv
+    // CHECK: call
+    // CHECK-SAME: void @llvm.assume(i1 %{{.+}})
+    // CHECK-NOT: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}
+    // CHECK-NOT: call
+    // CHECK-NOT: %{{.*}} = mul
+    // CHECK-NOT: %{{.*}} = udiv
+    // CHECK: ret void
+
+    vec.into_iter().map(|Wrapper(e)| e).collect()
+}
+
+// CHECK-LABEL: @vec_iterator_cast_wrap_drop
+#[no_mangle]
+pub fn vec_iterator_cast_wrap_drop(vec: Vec<String>) -> Vec<Wrapper<String>> {
+    // CHECK-NOT: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}
+    // CHECK-NOT: %{{.*}} = mul
+    // CHECK-NOT: %{{.*}} = udiv
+    // CHECK: call
+    // CHECK-SAME: void @llvm.assume(i1 %{{.+}})
+    // CHECK-NOT: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}
+    // CHECK-NOT: call
+    // CHECK-NOT: %{{.*}} = mul
+    // CHECK-NOT: %{{.*}} = udiv
+    // CHECK: ret void
+
+    vec.into_iter().map(Wrapper).collect()
+}
diff --git a/tests/codegen-llvm/vec-iter-collect-len.rs b/tests/codegen-llvm/vec-iter-collect-len.rs
new file mode 100644
index 00000000000..807548ef883
--- /dev/null
+++ b/tests/codegen-llvm/vec-iter-collect-len.rs
@@ -0,0 +1,12 @@
+//@ compile-flags: -Copt-level=3
+#![crate_type = "lib"]
+
+#[no_mangle]
+pub fn get_len() -> usize {
+    // CHECK-LABEL: @get_len
+    // CHECK-NEXT: start:
+    // CHECK-NEXT: ; call __rustc::__rust_no_alloc_shim_is_unstable_v2
+    // CHECK-NEXT: tail call void @_R{{.+}}__rust_no_alloc_shim_is_unstable_v2()
+    // CHECK-NEXT: ret i{{[0-9]+}} 3
+    [1, 2, 3].iter().collect::<Vec<_>>().len()
+}
diff --git a/tests/codegen-llvm/vec-iter.rs b/tests/codegen-llvm/vec-iter.rs
new file mode 100644
index 00000000000..4ed00d2d34f
--- /dev/null
+++ b/tests/codegen-llvm/vec-iter.rs
@@ -0,0 +1,58 @@
+//@ compile-flags: -Copt-level=3
+#![crate_type = "lib"]
+#![feature(exact_size_is_empty)]
+
+use std::vec;
+
+// CHECK-LABEL: @vec_iter_len_nonnull
+#[no_mangle]
+pub fn vec_iter_len_nonnull(it: &vec::IntoIter<u8>) -> usize {
+    // CHECK: load ptr
+    // CHECK-SAME: !nonnull
+    // CHECK-SAME: !noundef
+    // CHECK: load ptr
+    // CHECK-SAME: !nonnull
+    // CHECK-SAME: !noundef
+    // CHECK: sub nuw
+    // CHECK: ret
+    it.len()
+}
+
+// CHECK-LABEL: @vec_iter_is_empty_nonnull
+#[no_mangle]
+pub fn vec_iter_is_empty_nonnull(it: &vec::IntoIter<u8>) -> bool {
+    // CHECK: load ptr
+    // CHECK-SAME: !nonnull
+    // CHECK-SAME: !noundef
+    // CHECK: load ptr
+    // CHECK-SAME: !nonnull
+    // CHECK-SAME: !noundef
+    // CHECK: ret
+    it.is_empty()
+}
+
+// CHECK-LABEL: @vec_iter_next_nonnull
+#[no_mangle]
+pub fn vec_iter_next_nonnull(it: &mut vec::IntoIter<u8>) -> Option<u8> {
+    // CHECK: load ptr
+    // CHECK-SAME: !nonnull
+    // CHECK-SAME: !noundef
+    // CHECK: load ptr
+    // CHECK-SAME: !nonnull
+    // CHECK-SAME: !noundef
+    // CHECK: ret
+    it.next()
+}
+
+// CHECK-LABEL: @vec_iter_next_back_nonnull
+#[no_mangle]
+pub fn vec_iter_next_back_nonnull(it: &mut vec::IntoIter<u8>) -> Option<u8> {
+    // CHECK: load ptr
+    // CHECK-SAME: !nonnull
+    // CHECK-SAME: !noundef
+    // CHECK: load ptr
+    // CHECK-SAME: !nonnull
+    // CHECK-SAME: !noundef
+    // CHECK: ret
+    it.next_back()
+}
diff --git a/tests/codegen-llvm/vec-len-invariant.rs b/tests/codegen-llvm/vec-len-invariant.rs
new file mode 100644
index 00000000000..033181c2bfb
--- /dev/null
+++ b/tests/codegen-llvm/vec-len-invariant.rs
@@ -0,0 +1,16 @@
+//@ compile-flags: -Copt-level=3
+//@ only-64bit
+//
+// This test confirms that we do not reload the length of a Vec after growing it in push.
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @should_load_once
+#[no_mangle]
+pub fn should_load_once(v: &mut Vec<u8>) {
+    // CHECK: load i64
+    // CHECK: call {{.*}}grow_one
+    // CHECK-NOT: load i64
+    // CHECK: add {{.*}}, 1
+    v.push(1);
+}
diff --git a/tests/codegen-llvm/vec-optimizes-away.rs b/tests/codegen-llvm/vec-optimizes-away.rs
new file mode 100644
index 00000000000..93b55454b10
--- /dev/null
+++ b/tests/codegen-llvm/vec-optimizes-away.rs
@@ -0,0 +1,12 @@
+//@ compile-flags: -Copt-level=3
+#![crate_type = "lib"]
+
+#[no_mangle]
+pub fn sum_me() -> i32 {
+    // CHECK-LABEL: @sum_me
+    // CHECK-NEXT: {{^.*:$}}
+    // CHECK-NEXT: ; call __rustc::__rust_no_alloc_shim_is_unstable_v2
+    // CHECK-NEXT: tail call void @_R{{.+}}__rust_no_alloc_shim_is_unstable_v2()
+    // CHECK-NEXT: ret i32 6
+    vec![1, 2, 3].iter().sum::<i32>()
+}
diff --git a/tests/codegen-llvm/vec-reserve-extend.rs b/tests/codegen-llvm/vec-reserve-extend.rs
new file mode 100644
index 00000000000..4d3f23ccecf
--- /dev/null
+++ b/tests/codegen-llvm/vec-reserve-extend.rs
@@ -0,0 +1,14 @@
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @should_reserve_once
+#[no_mangle]
+pub fn should_reserve_once(v: &mut Vec<u8>) {
+    // CHECK: tail call void @llvm.assume
+    v.try_reserve(3).unwrap();
+    // CHECK-NOT: call {{.*}}reserve
+    // CHECK-NOT: call {{.*}}do_reserve_and_handle
+    // CHECK-NOT: call {{.*}}__rust_alloc(
+    v.extend([1, 2, 3]);
+}
diff --git a/tests/codegen-llvm/vec-shrink-panik.rs b/tests/codegen-llvm/vec-shrink-panik.rs
new file mode 100644
index 00000000000..23dd300d48c
--- /dev/null
+++ b/tests/codegen-llvm/vec-shrink-panik.rs
@@ -0,0 +1,31 @@
+// LLVM 17 realizes double panic is not possible and doesn't generate calls
+// to panic_cannot_unwind.
+//@ compile-flags: -Copt-level=3
+//@ ignore-std-debug-assertions (plain old debug assertions)
+//@ needs-unwind
+#![crate_type = "lib"]
+#![feature(shrink_to)]
+
+// Make sure that `Vec::shrink_to_fit` never emits panics via `RawVec::shrink_to_fit`,
+// "Tried to shrink to a larger capacity", because the length is *always* <= capacity.
+
+// CHECK-LABEL: @shrink_to_fit
+#[no_mangle]
+pub fn shrink_to_fit(vec: &mut Vec<u32>) {
+    // CHECK-NOT: panic
+    vec.shrink_to_fit();
+}
+
+// CHECK-LABEL: @issue71861
+#[no_mangle]
+pub fn issue71861(vec: Vec<u32>) -> Box<[u32]> {
+    // CHECK-NOT: panic
+    vec.into_boxed_slice()
+}
+
+// CHECK-LABEL: @issue75636
+#[no_mangle]
+pub fn issue75636<'a>(iter: &[&'a str]) -> Box<[&'a str]> {
+    // CHECK-NOT: panic
+    iter.iter().copied().collect()
+}
diff --git a/tests/codegen-llvm/vec-with-capacity.rs b/tests/codegen-llvm/vec-with-capacity.rs
new file mode 100644
index 00000000000..777bbcc4fcb
--- /dev/null
+++ b/tests/codegen-llvm/vec-with-capacity.rs
@@ -0,0 +1,35 @@
+//@ compile-flags: -Copt-level=3
+//@ ignore-std-debug-assertions
+// (with debug assertions turned on, `assert_unchecked` generates a real assertion)
+
+#![crate_type = "lib"]
+#![feature(try_with_capacity)]
+
+// CHECK-LABEL: @with_capacity_does_not_grow1
+#[no_mangle]
+pub fn with_capacity_does_not_grow1() -> Vec<u32> {
+    let v = Vec::with_capacity(1234);
+    // CHECK: call {{.*}}__rust_alloc(
+    // CHECK-NOT: call {{.*}}__rust_realloc
+    // CHECK-NOT: call {{.*}}capacity_overflow
+    // CHECK-NOT: call {{.*}}finish_grow
+    // CHECK-NOT: call {{.*}}reserve
+    // CHECK-NOT: memcpy
+    // CHECK-NOT: memset
+    v
+}
+
+// CHECK-LABEL: @try_with_capacity_does_not_grow2
+#[no_mangle]
+pub fn try_with_capacity_does_not_grow2() -> Option<Vec<Vec<u8>>> {
+    let v = Vec::try_with_capacity(1234).ok()?;
+    // CHECK: call {{.*}}__rust_alloc(
+    // CHECK-NOT: call {{.*}}__rust_realloc
+    // CHECK-NOT: call {{.*}}capacity_overflow
+    // CHECK-NOT: call {{.*}}finish_grow
+    // CHECK-NOT: call {{.*}}handle_alloc_error
+    // CHECK-NOT: call {{.*}}reserve
+    // CHECK-NOT: memcpy
+    // CHECK-NOT: memset
+    Some(v)
+}
diff --git a/tests/codegen-llvm/vec_pop_push_noop.rs b/tests/codegen-llvm/vec_pop_push_noop.rs
new file mode 100644
index 00000000000..3e375219fe0
--- /dev/null
+++ b/tests/codegen-llvm/vec_pop_push_noop.rs
@@ -0,0 +1,24 @@
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+
+#[no_mangle]
+// CHECK-LABEL: @noop(
+pub fn noop(v: &mut Vec<u8>) {
+    // CHECK-NOT: grow_one
+    // CHECK-NOT: call
+    // CHECK: tail call void @llvm.assume
+    // CHECK-NOT: grow_one
+    // CHECK-NOT: call
+    // CHECK: {{ret|[}]}}
+    if let Some(x) = v.pop() {
+        v.push(x)
+    }
+}
+
+#[no_mangle]
+// CHECK-LABEL: @push_byte(
+pub fn push_byte(v: &mut Vec<u8>) {
+    // CHECK: call {{.*}}grow_one
+    v.push(3);
+}
diff --git a/tests/codegen-llvm/vecdeque-drain.rs b/tests/codegen-llvm/vecdeque-drain.rs
new file mode 100644
index 00000000000..a5e5da65013
--- /dev/null
+++ b/tests/codegen-llvm/vecdeque-drain.rs
@@ -0,0 +1,70 @@
+// Check that draining at the front or back doesn't copy memory.
+
+//@ compile-flags: -Copt-level=3
+//@ needs-deterministic-layouts
+//@ ignore-std-debug-assertions (FIXME: checks for call detect scoped noalias metadata)
+
+#![crate_type = "lib"]
+
+use std::collections::VecDeque;
+
+// CHECK-LABEL: @clear
+// CHECK-NOT: call
+// CHECK-NOT: br
+// CHECK: getelementptr inbounds
+// CHECK-NEXT: {{call void @llvm.memset|store}}
+// CHECK-NEXT: ret void
+#[no_mangle]
+pub fn clear(v: &mut VecDeque<i32>) {
+    v.drain(..);
+}
+
+// CHECK-LABEL: @truncate
+// CHECK-NOT: call
+// CHECK: br
+// CHECK-NOT: call
+// CHECK: br
+// CHECK-NOT: call
+// CHECK: br
+// CHECK-NOT: call
+// CHECK: br
+// CHECK-NOT: call
+// CHECK-NOT: br
+// CHECK: ret void
+#[no_mangle]
+pub fn truncate(v: &mut VecDeque<i32>, n: usize) {
+    if n < v.len() {
+        v.drain(n..);
+    }
+}
+
+// CHECK-LABEL: @advance
+// CHECK-NOT: call
+// CHECK: br
+// CHECK-NOT: call
+// CHECK: br
+// CHECK-NOT: call
+// CHECK: br
+// CHECK-NOT: call
+// CHECK: br
+// CHECK-NOT: call
+// CHECK: br
+// CHECK-NOT: call
+// CHECK-NOT: br
+// CHECK: ret void
+#[no_mangle]
+pub fn advance(v: &mut VecDeque<i32>, n: usize) {
+    if n < v.len() {
+        v.drain(..n);
+    } else {
+        v.clear();
+    }
+}
+
+// CHECK-LABEL: @remove
+// CHECK: call
+// CHECK: ret void
+#[no_mangle]
+pub fn remove(v: &mut VecDeque<i32>, a: usize, b: usize) {
+    v.drain(a..b);
+}
diff --git a/tests/codegen-llvm/vecdeque-nonempty-get-no-panic.rs b/tests/codegen-llvm/vecdeque-nonempty-get-no-panic.rs
new file mode 100644
index 00000000000..1f886b096bb
--- /dev/null
+++ b/tests/codegen-llvm/vecdeque-nonempty-get-no-panic.rs
@@ -0,0 +1,16 @@
+// Guards against regression for optimization discussed in issue #80836
+
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+
+use std::collections::VecDeque;
+
+// CHECK-LABEL: @front
+// CHECK: ret void
+#[no_mangle]
+pub fn front(v: VecDeque<usize>) {
+    if !v.is_empty() {
+        v.get(0).unwrap();
+    }
+}
diff --git a/tests/codegen-llvm/vecdeque_no_panic.rs b/tests/codegen-llvm/vecdeque_no_panic.rs
new file mode 100644
index 00000000000..3166842afca
--- /dev/null
+++ b/tests/codegen-llvm/vecdeque_no_panic.rs
@@ -0,0 +1,19 @@
+// This test checks that `VecDeque::front[_mut]()` and `VecDeque::back[_mut]()` can't panic.
+
+//@ compile-flags: -Copt-level=3
+//@ ignore-std-debug-assertions (plain old debug assertions)
+
+#![crate_type = "lib"]
+
+use std::collections::VecDeque;
+
+// CHECK-LABEL: @dont_panic
+#[no_mangle]
+pub fn dont_panic(v: &mut VecDeque<usize>) {
+    // CHECK-NOT: expect
+    // CHECK-NOT: panic
+    v.front();
+    v.front_mut();
+    v.back();
+    v.back_mut();
+}
diff --git a/tests/codegen-llvm/vecdeque_pop_push.rs b/tests/codegen-llvm/vecdeque_pop_push.rs
new file mode 100644
index 00000000000..5afa1b2248b
--- /dev/null
+++ b/tests/codegen-llvm/vecdeque_pop_push.rs
@@ -0,0 +1,67 @@
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+
+use std::collections::VecDeque;
+
+#[no_mangle]
+// CHECK-LABEL: @noop_back(
+pub fn noop_back(v: &mut VecDeque<u8>) {
+    // CHECK-NOT: grow
+    // CHECK: tail call void @llvm.assume
+    // CHECK-NOT: grow
+    // CHECK: ret
+    if let Some(x) = v.pop_back() {
+        v.push_back(x);
+    }
+}
+
+#[no_mangle]
+// CHECK-LABEL: @noop_front(
+pub fn noop_front(v: &mut VecDeque<u8>) {
+    // CHECK-NOT: grow
+    // CHECK: tail call void @llvm.assume
+    // CHECK-NOT: grow
+    // CHECK: ret
+    if let Some(x) = v.pop_front() {
+        v.push_front(x);
+    }
+}
+
+#[no_mangle]
+// CHECK-LABEL: @move_byte_front_to_back(
+pub fn move_byte_front_to_back(v: &mut VecDeque<u8>) {
+    // CHECK-NOT: grow
+    // CHECK: tail call void @llvm.assume
+    // CHECK-NOT: grow
+    // CHECK: ret
+    if let Some(x) = v.pop_front() {
+        v.push_back(x);
+    }
+}
+
+#[no_mangle]
+// CHECK-LABEL: @move_byte_back_to_front(
+pub fn move_byte_back_to_front(v: &mut VecDeque<u8>) {
+    // CHECK-NOT: grow
+    // CHECK: tail call void @llvm.assume
+    // CHECK-NOT: grow
+    // CHECK: ret
+    if let Some(x) = v.pop_back() {
+        v.push_front(x);
+    }
+}
+
+#[no_mangle]
+// CHECK-LABEL: @push_back_byte(
+pub fn push_back_byte(v: &mut VecDeque<u8>) {
+    // CHECK: call {{.*}}grow
+    v.push_back(3);
+}
+
+#[no_mangle]
+// CHECK-LABEL: @push_front_byte(
+pub fn push_front_byte(v: &mut VecDeque<u8>) {
+    // CHECK: call {{.*}}grow
+    v.push_front(3);
+}
diff --git a/tests/codegen-llvm/virtual-call-attrs-issue-137646.rs b/tests/codegen-llvm/virtual-call-attrs-issue-137646.rs
new file mode 100644
index 00000000000..5e453947f27
--- /dev/null
+++ b/tests/codegen-llvm/virtual-call-attrs-issue-137646.rs
@@ -0,0 +1,37 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/137646.
+//! Since we don't know the exact implementation of the virtual call,
+//! it might write to parameters, we can't infer the readonly attribute.
+//@ compile-flags: -C opt-level=3 -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+#![feature(rustc_attrs)]
+
+pub trait Trait {
+    #[rustc_nounwind]
+    fn m(&self, _: (i32, i32, i32)) {}
+}
+
+#[no_mangle]
+pub fn foo(trait_: &dyn Trait) {
+    // CHECK-LABEL: @foo(
+    // CHECK: call void
+    // CHECK-NOT: readonly
+    trait_.m((1, 1, 1));
+}
+
+#[no_mangle]
+#[rustc_nounwind]
+pub fn foo_nounwind(trait_: &dyn Trait) {
+    // CHECK-LABEL: @foo_nounwind(
+    // FIXME: Here should be invoke.
+    // COM: CHECK: invoke
+    trait_.m((1, 1, 1));
+}
+
+#[no_mangle]
+pub extern "C" fn c_nounwind(trait_: &dyn Trait) {
+    // CHECK-LABEL: @c_nounwind(
+    // FIXME: Here should be invoke.
+    // COM: CHECK: invoke
+    trait_.m((1, 1, 1));
+}
diff --git a/tests/codegen-llvm/virtual-function-elimination-32bit.rs b/tests/codegen-llvm/virtual-function-elimination-32bit.rs
new file mode 100644
index 00000000000..c9919cecccf
--- /dev/null
+++ b/tests/codegen-llvm/virtual-function-elimination-32bit.rs
@@ -0,0 +1,35 @@
+//@ compile-flags: -Zvirtual-function-elimination -Clto -Copt-level=3 -Csymbol-mangling-version=v0
+//@ ignore-64bit
+
+// CHECK: @vtable.0 = {{.*}}, !type ![[TYPE0:[0-9]+]], !vcall_visibility ![[VCALL_VIS0:[0-9]+]]
+
+#![crate_type = "lib"]
+
+trait T {
+    // CHECK-LABEL: ; <virtual_function_elimination_32bit::S as virtual_function_elimination_32bit::T>::used
+    fn used(&self) -> i32 {
+        1
+    }
+    // CHECK-LABEL-NOT: {{.*}}::unused
+    fn unused(&self) -> i32 {
+        2
+    }
+}
+
+#[derive(Copy, Clone)]
+struct S;
+
+impl T for S {}
+
+fn taking_t(t: &dyn T) -> i32 {
+    // CHECK: @llvm.type.checked.load({{.*}}, i32 12, metadata !"[[MANGLED_TYPE0:[0-9a-zA-Z_]+]]")
+    t.used()
+}
+
+pub fn main() {
+    let s = S;
+    taking_t(&s);
+}
+
+// CHECK: ![[TYPE0]] = !{i32 0, !"[[MANGLED_TYPE0]]"}
+// CHECK: ![[VCALL_VIS0]] = !{i64 2}
diff --git a/tests/codegen-llvm/virtual-function-elimination.rs b/tests/codegen-llvm/virtual-function-elimination.rs
new file mode 100644
index 00000000000..26604478c11
--- /dev/null
+++ b/tests/codegen-llvm/virtual-function-elimination.rs
@@ -0,0 +1,98 @@
+//@ compile-flags: -Zvirtual-function-elimination -Clto -Copt-level=3 -Csymbol-mangling-version=v0
+//@ ignore-32bit
+
+// CHECK: @vtable.0 = {{.*}}, !type ![[TYPE0:[0-9]+]], !vcall_visibility ![[VCALL_VIS0:[0-9]+]]
+// CHECK: @vtable.1 = {{.*}}, !type ![[TYPE1:[0-9]+]], !vcall_visibility ![[VCALL_VIS0:[0-9]+]]
+// CHECK: @vtable.2 = {{.*}}, !type ![[TYPE2:[0-9]+]], !vcall_visibility ![[VCALL_VIS2:[0-9]+]]
+
+#![crate_type = "lib"]
+
+use std::rc::Rc;
+
+trait T {
+    // CHECK-LABEL: ; <virtual_function_elimination::S as virtual_function_elimination::T>::used
+    fn used(&self) -> i32 {
+        1
+    }
+    // CHECK-LABEL: ; <virtual_function_elimination::S as virtual_function_elimination::T>::used_through_sub_trait
+    fn used_through_sub_trait(&self) -> i32 {
+        3
+    }
+    // CHECK-LABEL: ; <virtual_function_elimination::S as virtual_function_elimination::T>::by_rc
+    fn by_rc(self: Rc<Self>) -> i32 {
+        self.used() + self.used()
+    }
+    // CHECK-LABEL-NOT: {{.*}}::unused
+    fn unused(&self) -> i32 {
+        2
+    }
+    // CHECK-LABEL-NOT: {{.*}}::by_rc_unused
+    fn by_rc_unused(self: Rc<Self>) -> i32 {
+        self.by_rc()
+    }
+}
+
+trait U: T {
+    // CHECK-LABEL: ; <virtual_function_elimination::S as virtual_function_elimination::U>::subtrait_used
+    fn subtrait_used(&self) -> i32 {
+        4
+    }
+    // CHECK-LABEL-NOT: {{.*}}::subtrait_unused
+    fn subtrait_unused(&self) -> i32 {
+        5
+    }
+}
+
+pub trait V {
+    // CHECK-LABEL: ; <virtual_function_elimination::S as virtual_function_elimination::V>::public_function
+    fn public_function(&self) -> i32;
+}
+
+#[derive(Copy, Clone)]
+struct S;
+
+impl T for S {}
+
+impl U for S {}
+
+impl V for S {
+    fn public_function(&self) -> i32 {
+        6
+    }
+}
+
+fn taking_t(t: &dyn T) -> i32 {
+    // CHECK: @llvm.type.checked.load({{.*}}, i32 24, metadata !"[[MANGLED_TYPE0:[0-9a-zA-Z_]+]]")
+    t.used()
+}
+
+fn taking_rc_t(t: Rc<dyn T>) -> i32 {
+    // CHECK: @llvm.type.checked.load({{.*}}, i32 40, metadata !"[[MANGLED_TYPE0:[0-9a-zA-Z_]+]]")
+    t.by_rc()
+}
+
+fn taking_u(u: &dyn U) -> i32 {
+    // CHECK: @llvm.type.checked.load({{.*}}, i32 64, metadata !"[[MANGLED_TYPE1:[0-9a-zA-Z_]+]]")
+    // CHECK: @llvm.type.checked.load({{.*}}, i32 24, metadata !"[[MANGLED_TYPE1:[0-9a-zA-Z_]+]]")
+    // CHECK: @llvm.type.checked.load({{.*}}, i32 32, metadata !"[[MANGLED_TYPE1:[0-9a-zA-Z_]+]]")
+    u.subtrait_used() + u.used() + u.used_through_sub_trait()
+}
+
+pub fn taking_v(v: &dyn V) -> i32 {
+    // CHECK: @llvm.type.checked.load({{.*}}, i32 24, metadata !"NtC[[CRATE_IDENT:[a-zA-Z0-9]{12}]]_28virtual_function_elimination1V")
+    v.public_function()
+}
+
+pub fn main() {
+    let s = S;
+    taking_t(&s);
+    taking_rc_t(Rc::new(s));
+    taking_u(&s);
+    taking_v(&s);
+}
+
+// CHECK: ![[TYPE0]] = !{i64 0, !"[[MANGLED_TYPE0]]"}
+// CHECK: ![[VCALL_VIS0]] = !{i64 2}
+// CHECK: ![[TYPE1]] = !{i64 0, !"[[MANGLED_TYPE1]]"}
+// CHECK: ![[TYPE2]] = !{i64 0, !"NtC[[CRATE_IDENT]]_28virtual_function_elimination1V"}
+// CHECK: ![[VCALL_VIS2]] = !{i64 1}
diff --git a/tests/codegen-llvm/vtable-loads.rs b/tests/codegen-llvm/vtable-loads.rs
new file mode 100644
index 00000000000..aa103ec6f7c
--- /dev/null
+++ b/tests/codegen-llvm/vtable-loads.rs
@@ -0,0 +1,16 @@
+//@ compile-flags: -Copt-level=3
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @loop_skips_vtable_load
+#[no_mangle]
+pub fn loop_skips_vtable_load(x: &dyn Fn()) {
+    // CHECK: load ptr, ptr %0{{.*}}, !invariant.load
+    // CHECK-NEXT: tail call void %1
+    // CHECK-NOT: load ptr
+    x();
+    for _ in 0..100 {
+        // CHECK: tail call void %1
+        x();
+    }
+}
diff --git a/tests/codegen-llvm/vtable-upcast.rs b/tests/codegen-llvm/vtable-upcast.rs
new file mode 100644
index 00000000000..9e13e8dd68a
--- /dev/null
+++ b/tests/codegen-llvm/vtable-upcast.rs
@@ -0,0 +1,84 @@
+//! This file tests that we correctly generate GEP instructions for vtable upcasting.
+//@ compile-flags: -C no-prepopulate-passes -Copt-level=0
+
+#![crate_type = "lib"]
+
+pub trait Base {
+    fn base(&self);
+}
+
+pub trait A: Base {
+    fn a(&self);
+}
+
+pub trait B: Base {
+    fn b(&self);
+}
+
+pub trait Diamond: A + B {
+    fn diamond(&self);
+}
+
+// CHECK-LABEL: upcast_a_to_base
+#[no_mangle]
+pub fn upcast_a_to_base(x: &dyn A) -> &dyn Base {
+    // Requires no adjustment, since its vtable is extended from `Base`.
+
+    // CHECK: start:
+    // CHECK-NEXT: insertvalue
+    // CHECK-NEXT: insertvalue
+    // CHECK-NEXT: ret
+    x as &dyn Base
+}
+
+// CHECK-LABEL: upcast_b_to_base
+#[no_mangle]
+pub fn upcast_b_to_base(x: &dyn B) -> &dyn Base {
+    // Requires no adjustment, since its vtable is extended from `Base`.
+
+    // CHECK: start:
+    // CHECK-NEXT: insertvalue
+    // CHECK-NEXT: insertvalue
+    // CHECK-NEXT: ret
+    x as &dyn Base
+}
+
+// CHECK-LABEL: upcast_diamond_to_a
+#[no_mangle]
+pub fn upcast_diamond_to_a(x: &dyn Diamond) -> &dyn A {
+    // Requires no adjustment, since its vtable is extended from `A` (as the first supertrait).
+
+    // CHECK: start:
+    // CHECK-NEXT: insertvalue
+    // CHECK-NEXT: insertvalue
+    // CHECK-NEXT: ret
+    x as &dyn A
+}
+
+// CHECK-LABEL: upcast_diamond_to_b
+// CHECK-SAME: (ptr align {{[0-9]+}} [[DATA_PTR:%.+]], ptr align {{[0-9]+}} [[VTABLE_PTR:%.+]])
+#[no_mangle]
+pub fn upcast_diamond_to_b(x: &dyn Diamond) -> &dyn B {
+    // Requires adjustment, since it's a non-first supertrait.
+
+    // CHECK: start:
+    // CHECK-NEXT: [[UPCAST_SLOT_PTR:%.+]] = getelementptr inbounds i8, ptr [[VTABLE_PTR]]
+    // CHECK-NEXT: [[UPCAST_VTABLE_PTR:%.+]] = load ptr, ptr [[UPCAST_SLOT_PTR]]
+    // CHECK-NEXT: [[FAT_PTR_1:%.+]] = insertvalue { ptr, ptr } poison, ptr [[DATA_PTR]], 0
+    // CHECK-NEXT: [[FAT_PTR_2:%.+]] = insertvalue { ptr, ptr } [[FAT_PTR_1]], ptr [[UPCAST_VTABLE_PTR]], 1
+    // CHECK-NEXT: ret { ptr, ptr } [[FAT_PTR_2]]
+    x as &dyn B
+}
+
+// CHECK-LABEL: upcast_diamond_to_b
+#[no_mangle]
+pub fn upcast_diamond_to_base(x: &dyn Diamond) -> &dyn Base {
+    // Requires no adjustment, since `Base` is the first supertrait of `A`,
+    // which is the first supertrait of `Diamond`.
+
+    // CHECK: start:
+    // CHECK-NEXT: insertvalue
+    // CHECK-NEXT: insertvalue
+    // CHECK-NEXT: ret
+    x as &dyn Base
+}
diff --git a/tests/codegen-llvm/wasm_casts_trapping.rs b/tests/codegen-llvm/wasm_casts_trapping.rs
new file mode 100644
index 00000000000..0908acd85fc
--- /dev/null
+++ b/tests/codegen-llvm/wasm_casts_trapping.rs
@@ -0,0 +1,157 @@
+//@ only-wasm32
+//@ compile-flags: -C target-feature=-nontrapping-fptoint
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @cast_f64_i64
+#[no_mangle]
+pub fn cast_f64_i64(a: f64) -> i64 {
+    // CHECK-NOT: fptosi double {{.*}} to i64
+    // CHECK-NOT: select i1 {{.*}}, i64 {{.*}}, i64 {{.*}}
+    // CHECK: {{.*}} call {{.*}} @llvm.fptosi.sat.i64.f64{{.*}}
+    a as _
+}
+
+// CHECK-LABEL: @cast_f64_i32
+#[no_mangle]
+pub fn cast_f64_i32(a: f64) -> i32 {
+    // CHECK-NOT: fptosi double {{.*}} to i32
+    // CHECK-NOT: select i1 {{.*}}, i32 {{.*}}, i32 {{.*}}
+    // CHECK: {{.*}} call {{.*}} @llvm.fptosi.sat.i32.f64{{.*}}
+    a as _
+}
+
+// CHECK-LABEL: @cast_f32_i64
+#[no_mangle]
+pub fn cast_f32_i64(a: f32) -> i64 {
+    // CHECK-NOT: fptosi float {{.*}} to i64
+    // CHECK-NOT: select i1 {{.*}}, i64 {{.*}}, i64 {{.*}}
+    // CHECK: {{.*}} call {{.*}} @llvm.fptosi.sat.i64.f32{{.*}}
+    a as _
+}
+
+// CHECK-LABEL: @cast_f32_i32
+#[no_mangle]
+pub fn cast_f32_i32(a: f32) -> i32 {
+    // CHECK-NOT: fptosi float {{.*}} to i32
+    // CHECK-NOT: select i1 {{.*}}, i32 {{.*}}, i32 {{.*}}
+    // CHECK: {{.*}} call {{.*}} @llvm.fptosi.sat.i32.f32{{.*}}
+    a as _
+}
+
+// CHECK-LABEL: @cast_f64_u64
+#[no_mangle]
+pub fn cast_f64_u64(a: f64) -> u64 {
+    // CHECK-NOT: fptoui double {{.*}} to i64
+    // CHECK-NOT: select i1 {{.*}}, i64 {{.*}}, i64 {{.*}}
+    // CHECK: {{.*}} call {{.*}} @llvm.fptoui.sat.i64.f64{{.*}}
+    a as _
+}
+
+// CHECK-LABEL: @cast_f64_u32
+#[no_mangle]
+pub fn cast_f64_u32(a: f64) -> u32 {
+    // CHECK-NOT: fptoui double {{.*}} to i32
+    // CHECK-NOT: select i1 {{.*}}, i32 {{.*}}, i32 {{.*}}
+    // CHECK: {{.*}} call {{.*}} @llvm.fptoui.sat.i32.f64{{.*}}
+    a as _
+}
+
+// CHECK-LABEL: @cast_f32_u64
+#[no_mangle]
+pub fn cast_f32_u64(a: f32) -> u64 {
+    // CHECK-NOT: fptoui float {{.*}} to i64
+    // CHECK-NOT: select i1 {{.*}}, i64 {{.*}}, i64 {{.*}}
+    // CHECK: {{.*}} call {{.*}} @llvm.fptoui.sat.i64.f32{{.*}}
+    a as _
+}
+
+// CHECK-LABEL: @cast_f32_u32
+#[no_mangle]
+pub fn cast_f32_u32(a: f32) -> u32 {
+    // CHECK-NOT: fptoui float {{.*}} to i32
+    // CHECK-NOT: select i1 {{.*}}, i32 {{.*}}, i32 {{.*}}
+    // CHECK: {{.*}} call {{.*}} @llvm.fptoui.sat.i32.f32{{.*}}
+    a as _
+}
+
+// CHECK-LABEL: @cast_f32_u8
+#[no_mangle]
+pub fn cast_f32_u8(a: f32) -> u8 {
+    // CHECK-NOT: fptoui float {{.*}} to i8
+    // CHECK-NOT: select i1 {{.*}}, i8 {{.*}}, i8 {{.*}}
+    // CHECK: {{.*}} call {{.*}} @llvm.fptoui.sat.i8.f32{{.*}}
+    a as _
+}
+
+// CHECK-LABEL: @cast_unchecked_f64_i64
+#[no_mangle]
+pub unsafe fn cast_unchecked_f64_i64(a: f64) -> i64 {
+    // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.signed.{{.*}}
+    // CHECK-NEXT: ret i64 {{.*}}
+    a.to_int_unchecked()
+}
+
+// CHECK-LABEL: @cast_unchecked_f64_i32
+#[no_mangle]
+pub unsafe fn cast_unchecked_f64_i32(a: f64) -> i32 {
+    // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.signed.{{.*}}
+    // CHECK-NEXT: ret i32 {{.*}}
+    a.to_int_unchecked()
+}
+
+// CHECK-LABEL: @cast_unchecked_f32_i64
+#[no_mangle]
+pub unsafe fn cast_unchecked_f32_i64(a: f32) -> i64 {
+    // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.signed.{{.*}}
+    // CHECK-NEXT: ret i64 {{.*}}
+    a.to_int_unchecked()
+}
+
+// CHECK-LABEL: @cast_unchecked_f32_i32
+#[no_mangle]
+pub unsafe fn cast_unchecked_f32_i32(a: f32) -> i32 {
+    // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.signed.{{.*}}
+    // CHECK-NEXT: ret i32 {{.*}}
+    a.to_int_unchecked()
+}
+
+// CHECK-LABEL: @cast_unchecked_f64_u64
+#[no_mangle]
+pub unsafe fn cast_unchecked_f64_u64(a: f64) -> u64 {
+    // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.unsigned.{{.*}}
+    // CHECK-NEXT: ret i64 {{.*}}
+    a.to_int_unchecked()
+}
+
+// CHECK-LABEL: @cast_unchecked_f64_u32
+#[no_mangle]
+pub unsafe fn cast_unchecked_f64_u32(a: f64) -> u32 {
+    // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.unsigned.{{.*}}
+    // CHECK-NEXT: ret i32 {{.*}}
+    a.to_int_unchecked()
+}
+
+// CHECK-LABEL: @cast_unchecked_f32_u64
+#[no_mangle]
+pub unsafe fn cast_unchecked_f32_u64(a: f32) -> u64 {
+    // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.unsigned.{{.*}}
+    // CHECK-NEXT: ret i64 {{.*}}
+    a.to_int_unchecked()
+}
+
+// CHECK-LABEL: @cast_unchecked_f32_u32
+#[no_mangle]
+pub unsafe fn cast_unchecked_f32_u32(a: f32) -> u32 {
+    // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.unsigned.{{.*}}
+    // CHECK-NEXT: ret i32 {{.*}}
+    a.to_int_unchecked()
+}
+
+// CHECK-LABEL: @cast_unchecked_f32_u8
+#[no_mangle]
+pub unsafe fn cast_unchecked_f32_u8(a: f32) -> u8 {
+    // CHECK-NOT: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}}
+    // CHECK: fptoui float {{.*}} to i8
+    // CHECK-NEXT: ret i8 {{.*}}
+    a.to_int_unchecked()
+}
diff --git a/tests/codegen-llvm/wasm_exceptions.rs b/tests/codegen-llvm/wasm_exceptions.rs
new file mode 100644
index 00000000000..07b8ae6e9d7
--- /dev/null
+++ b/tests/codegen-llvm/wasm_exceptions.rs
@@ -0,0 +1,59 @@
+//@ only-wasm32
+//@ compile-flags: -C panic=unwind -Z emscripten-wasm-eh
+
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+extern "C-unwind" {
+    fn may_panic();
+}
+
+extern "C" {
+    fn log_number(number: usize);
+}
+
+struct LogOnDrop;
+
+impl Drop for LogOnDrop {
+    fn drop(&mut self) {
+        unsafe {
+            log_number(0);
+        }
+    }
+}
+
+// CHECK-LABEL: @test_cleanup() {{.*}} @__gxx_wasm_personality_v0
+#[no_mangle]
+pub fn test_cleanup() {
+    let _log_on_drop = LogOnDrop;
+    unsafe {
+        may_panic();
+    }
+
+    // CHECK-NOT: call
+    // CHECK: invoke void @may_panic()
+    // CHECK: %cleanuppad = cleanuppad within none []
+}
+
+// CHECK-LABEL: @test_rtry() {{.*}} @__gxx_wasm_personality_v0
+#[no_mangle]
+pub fn test_rtry() {
+    unsafe {
+        core::intrinsics::catch_unwind(
+            |_| {
+                may_panic();
+            },
+            core::ptr::null_mut(),
+            |data, exception| {
+                log_number(data as usize);
+                log_number(exception as usize);
+            },
+        );
+    }
+
+    // CHECK-NOT: call
+    // CHECK: invoke void @may_panic()
+    // CHECK: {{.*}} = catchswitch within none [label {{.*}}] unwind to caller
+    // CHECK: {{.*}} = catchpad within {{.*}} [ptr null]
+    // CHECK: catchret
+}
diff --git a/tests/codegen-llvm/zip.rs b/tests/codegen-llvm/zip.rs
new file mode 100644
index 00000000000..38ecf7c15c6
--- /dev/null
+++ b/tests/codegen-llvm/zip.rs
@@ -0,0 +1,21 @@
+//@ compile-flags: -Cno-prepopulate-passes -Copt-level=3
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @zip_copy
+#[no_mangle]
+pub fn zip_copy(xs: &[u8], ys: &mut [u8]) {
+    // CHECK: memcpy
+    for (x, y) in xs.iter().zip(ys) {
+        *y = *x;
+    }
+}
+
+// CHECK-LABEL: @zip_copy_mapped
+#[no_mangle]
+pub fn zip_copy_mapped(xs: &[u8], ys: &mut [u8]) {
+    // CHECK: memcpy
+    for (x, y) in xs.iter().map(|&x| x).zip(ys) {
+        *y = x;
+    }
+}
diff --git a/tests/codegen-llvm/zst-offset.rs b/tests/codegen-llvm/zst-offset.rs
new file mode 100644
index 00000000000..475394a8815
--- /dev/null
+++ b/tests/codegen-llvm/zst-offset.rs
@@ -0,0 +1,42 @@
+//@ compile-flags: -C no-prepopulate-passes -Copt-level=0
+
+#![crate_type = "lib"]
+#![feature(repr_simd)]
+
+// Hack to get the correct size for the length part in slices
+// CHECK: @helper([[USIZE:i[0-9]+]] %_1)
+#[no_mangle]
+pub fn helper(_: usize) {}
+
+// Check that we correctly generate a GEP for a ZST that is not included in Scalar layout
+// CHECK-LABEL: @scalar_layout
+#[no_mangle]
+pub fn scalar_layout(s: &(u64, ())) {
+    // CHECK: getelementptr inbounds i8, {{.+}}, [[USIZE]] 8
+    let x = &s.1;
+    witness(&x); // keep variable in an alloca
+}
+
+// Check that we correctly generate a GEP for a ZST that is not included in ScalarPair layout
+// CHECK-LABEL: @scalarpair_layout
+#[no_mangle]
+pub fn scalarpair_layout(s: &(u64, u32, ())) {
+    // CHECK: getelementptr inbounds i8, {{.+}}, [[USIZE]] 12
+    let x = &s.2;
+    witness(&x); // keep variable in an alloca
+}
+
+#[repr(simd)]
+pub struct U64x4([u64; 4]);
+
+// Check that we correctly generate a GEP for a ZST that is not included in Vector layout
+// CHECK-LABEL: @vector_layout
+#[no_mangle]
+pub fn vector_layout(s: &(U64x4, ())) {
+    // CHECK: getelementptr inbounds i8, {{.+}}, [[USIZE]] 32
+    let x = &s.1;
+    witness(&x); // keep variable in an alloca
+}
+
+#[inline(never)]
+fn witness(_: &impl Sized) {}