summaryrefslogtreecommitdiffstats
path: root/tests/codegen
diff options
context:
space:
mode:
Diffstat (limited to 'tests/codegen')
-rw-r--r--tests/codegen/README.md24
-rw-r--r--tests/codegen/abi-efiapi.rs33
-rw-r--r--tests/codegen/abi-main-signature-16bit-c-int.rs25
-rw-r--r--tests/codegen/abi-main-signature-32bit-c-int.rs10
-rw-r--r--tests/codegen/abi-repr-ext.rs57
-rw-r--r--tests/codegen/abi-sysv64.rs22
-rw-r--r--tests/codegen/abi-x86-interrupt.rs22
-rw-r--r--tests/codegen/abi-x86_64_sysv.rs29
-rw-r--r--tests/codegen/adjustments.rs29
-rw-r--r--tests/codegen/align-enum.rs34
-rw-r--r--tests/codegen/align-fn.rs9
-rw-r--r--tests/codegen/align-struct.rs71
-rw-r--r--tests/codegen/alloc-optimisation.rs13
-rw-r--r--tests/codegen/array-clone.rs15
-rw-r--r--tests/codegen/array-equality.rs74
-rw-r--r--tests/codegen/asm-clobber_abi.rs36
-rw-r--r--tests/codegen/asm-clobbers.rs20
-rw-r--r--tests/codegen/asm-may_unwind.rs39
-rw-r--r--tests/codegen/asm-multiple-options.rs54
-rw-r--r--tests/codegen/asm-options.rs104
-rw-r--r--tests/codegen/asm-powerpc-clobbers.rs47
-rw-r--r--tests/codegen/asm-sanitize-llvm.rs34
-rw-r--r--tests/codegen/asm-target-clobbers.rs29
-rw-r--r--tests/codegen/async-fn-debug-awaitee-field.rs25
-rw-r--r--tests/codegen/async-fn-debug-msvc.rs54
-rw-r--r--tests/codegen/async-fn-debug.rs58
-rw-r--r--tests/codegen/atomic-operations.rs83
-rw-r--r--tests/codegen/autovectorize-f32x4.rs32
-rw-r--r--tests/codegen/auxiliary/extern_decl.rs11
-rw-r--r--tests/codegen/auxiliary/nounwind.rs3
-rw-r--r--tests/codegen/auxiliary/static_dllimport_aux.rs13
-rw-r--r--tests/codegen/auxiliary/thread_local_aux.rs5
-rw-r--r--tests/codegen/avr/avr-func-addrspace.rs111
-rw-r--r--tests/codegen/binary-search-index-no-bound-check.rs38
-rw-r--r--tests/codegen/bool-cmp.rs18
-rw-r--r--tests/codegen/box-maybe-uninit-llvm14.rs34
-rw-r--r--tests/codegen/box-maybe-uninit.rs33
-rw-r--r--tests/codegen/bpf-alu32.rs11
-rw-r--r--tests/codegen/branch-protection.rs45
-rw-r--r--tests/codegen/c-variadic-copy.rs16
-rw-r--r--tests/codegen/c-variadic-opt.rs30
-rw-r--r--tests/codegen/c-variadic.rs72
-rw-r--r--tests/codegen/call-llvm-intrinsics.rs29
-rw-r--r--tests/codegen/call-metadata.rs17
-rw-r--r--tests/codegen/catch-unwind.rs31
-rw-r--r--tests/codegen/cdylib-external-inline-fns.rs43
-rw-r--r--tests/codegen/cf-protection.rs38
-rw-r--r--tests/codegen/cfguard-checks.rs11
-rw-r--r--tests/codegen/cfguard-disabled.rs11
-rw-r--r--tests/codegen/cfguard-nochecks.rs11
-rw-r--r--tests/codegen/cfguard-non-msvc.rs11
-rw-r--r--tests/codegen/codemodels.rs20
-rw-r--r--tests/codegen/coercions.rs19
-rw-r--r--tests/codegen/cold-call-declare-and-call.rs18
-rw-r--r--tests/codegen/comparison-operators-newtype.rs49
-rw-r--r--tests/codegen/consts.rs56
-rw-r--r--tests/codegen/dealloc-no-unwind.rs22
-rw-r--r--tests/codegen/debug-alignment.rs8
-rw-r--r--tests/codegen/debug-column-msvc.rs16
-rw-r--r--tests/codegen/debug-column.rs24
-rw-r--r--tests/codegen/debug-compile-unit-path.rs9
-rw-r--r--tests/codegen/debug-linkage-name.rs42
-rw-r--r--tests/codegen/debug-vtable.rs107
-rw-r--r--tests/codegen/debuginfo-generic-closure-env-names.rs89
-rw-r--r--tests/codegen/deduced-param-attrs.rs60
-rw-r--r--tests/codegen/default-requires-uwtable.rs16
-rw-r--r--tests/codegen/dllimports/auxiliary/dummy.rs6
-rw-r--r--tests/codegen/dllimports/auxiliary/wrapper.rs14
-rw-r--r--tests/codegen/dllimports/main.rs43
-rw-r--r--tests/codegen/drop.rs36
-rw-r--r--tests/codegen/dst-vtable-align-nonzero.rs61
-rw-r--r--tests/codegen/dst-vtable-size-range.rs35
-rw-r--r--tests/codegen/enum-bounds-check-derived-idx.rs24
-rw-r--r--tests/codegen/enum-bounds-check-issue-13926.rs18
-rw-r--r--tests/codegen/enum-bounds-check-issue-82871.rs18
-rw-r--r--tests/codegen/enum-bounds-check.rs26
-rw-r--r--tests/codegen/enum-debug-clike.rs23
-rw-r--r--tests/codegen/enum-debug-niche-2.rs50
-rw-r--r--tests/codegen/enum-debug-niche.rs29
-rw-r--r--tests/codegen/enum-debug-tagged.rs27
-rw-r--r--tests/codegen/enum-discriminant-value.rs27
-rw-r--r--tests/codegen/enum-match.rs109
-rw-r--r--tests/codegen/export-no-mangle.rs31
-rw-r--r--tests/codegen/external-no-mangle-fns.rs75
-rw-r--r--tests/codegen/external-no-mangle-statics.rs77
-rw-r--r--tests/codegen/fastcall-inreg.rs41
-rw-r--r--tests/codegen/fatptr.rs12
-rw-r--r--tests/codegen/fewer-names.rs20
-rw-r--r--tests/codegen/ffi-const.rs13
-rw-r--r--tests/codegen/ffi-out-of-bounds-loads.rs25
-rw-r--r--tests/codegen/ffi-pure.rs13
-rw-r--r--tests/codegen/ffi-returns-twice.rs11
-rw-r--r--tests/codegen/float_math.rs50
-rw-r--r--tests/codegen/fn-impl-trait-self.rs16
-rw-r--r--tests/codegen/foo.s3
-rw-r--r--tests/codegen/force-frame-pointers.rs6
-rw-r--r--tests/codegen/force-no-unwind-tables.rs11
-rw-r--r--tests/codegen/force-unwind-tables.rs6
-rw-r--r--tests/codegen/frame-pointer.rs35
-rw-r--r--tests/codegen/function-arguments-noopt.rs63
-rw-r--r--tests/codegen/function-arguments.rs261
-rw-r--r--tests/codegen/gdb_debug_script_load.rs17
-rw-r--r--tests/codegen/generator-debug-msvc.rs59
-rw-r--r--tests/codegen/generator-debug.rs62
-rw-r--r--tests/codegen/generic-debug.rs17
-rw-r--r--tests/codegen/global_asm.rs64
-rw-r--r--tests/codegen/global_asm_include.rs57
-rw-r--r--tests/codegen/global_asm_x2.rs83
-rw-r--r--tests/codegen/i686-macosx-deployment-target.rs27
-rw-r--r--tests/codegen/i686-no-macosx-deployment-target.rs27
-rw-r--r--tests/codegen/inline-always-works-always.rs21
-rw-r--r--tests/codegen/inline-debuginfo.rs17
-rw-r--r--tests/codegen/inline-hint.rs31
-rw-r--r--tests/codegen/instrument-coverage.rs17
-rw-r--r--tests/codegen/instrument-mcount.rs7
-rw-r--r--tests/codegen/integer-cmp.rs28
-rw-r--r--tests/codegen/integer-overflow.rs26
-rw-r--r--tests/codegen/internalize-closures.rs14
-rw-r--r--tests/codegen/intrinsic-no-unnamed-attr.rs12
-rw-r--r--tests/codegen/intrinsics/const_eval_select.rs18
-rw-r--r--tests/codegen/intrinsics/exact_div.rs20
-rw-r--r--tests/codegen/intrinsics/likely.rs30
-rw-r--r--tests/codegen/intrinsics/mask.rs12
-rw-r--r--tests/codegen/intrinsics/nearby.rs18
-rw-r--r--tests/codegen/intrinsics/nontemporal.rs13
-rw-r--r--tests/codegen/intrinsics/offset_from.rs36
-rw-r--r--tests/codegen/intrinsics/prefetch.rs63
-rw-r--r--tests/codegen/intrinsics/unchecked_math.rs46
-rw-r--r--tests/codegen/intrinsics/volatile.rs55
-rw-r--r--tests/codegen/intrinsics/volatile_order.rs18
-rw-r--r--tests/codegen/issue-103285-ptr-addr-overflow-check.rs16
-rw-r--r--tests/codegen/issue-103840.rs9
-rw-r--r--tests/codegen/issue-105386-ub-in-debuginfo.rs22
-rw-r--r--tests/codegen/issue-13018.rs11
-rw-r--r--tests/codegen/issue-15953.rs29
-rw-r--r--tests/codegen/issue-27130.rs21
-rw-r--r--tests/codegen/issue-32031.rs23
-rw-r--r--tests/codegen/issue-32364.rs18
-rw-r--r--tests/codegen/issue-34634.rs16
-rw-r--r--tests/codegen/issue-34947-pow-i32.rs13
-rw-r--r--tests/codegen/issue-37945.rs38
-rw-r--r--tests/codegen/issue-44056-macos-tls-align.rs28
-rw-r--r--tests/codegen/issue-45222.rs63
-rw-r--r--tests/codegen/issue-45466.rs15
-rw-r--r--tests/codegen/issue-45964-bounds-check-slice-pos.rs39
-rw-r--r--tests/codegen/issue-47278.rs9
-rw-r--r--tests/codegen/issue-47442.rs22
-rw-r--r--tests/codegen/issue-56267-2.rs18
-rw-r--r--tests/codegen/issue-56267.rs18
-rw-r--r--tests/codegen/issue-56927.rs43
-rw-r--r--tests/codegen/issue-58881.rs21
-rw-r--r--tests/codegen/issue-59352.rs18
-rw-r--r--tests/codegen/issue-69101-bounds-check.rs44
-rw-r--r--tests/codegen/issue-73031.rs26
-rw-r--r--tests/codegen/issue-73338-effecient-cmp.rs39
-rw-r--r--tests/codegen/issue-73396-bounds-check-after-position.rs77
-rw-r--r--tests/codegen/issue-73827-bounds-check-index-in-subexpr.rs17
-rw-r--r--tests/codegen/issue-75525-bounds-checks.rs26
-rw-r--r--tests/codegen/issue-75546.rs15
-rw-r--r--tests/codegen/issue-75659.rs63
-rw-r--r--tests/codegen/issue-77812.rs32
-rw-r--r--tests/codegen/issue-81408-dllimport-thinlto-windows.rs15
-rw-r--r--tests/codegen/issue-84268.rs23
-rw-r--r--tests/codegen/issue-85872-multiple-reverse.rs20
-rw-r--r--tests/codegen/issue-86106.rs62
-rw-r--r--tests/codegen/issue-96274.rs17
-rw-r--r--tests/codegen/issue-96497-slice-size-nowrap.rs29
-rw-r--r--tests/codegen/issue-98156-const-arg-temp-lifetime.rs27
-rw-r--r--tests/codegen/issue-98294-get-mut-copy-from-slice-opt.rs19
-rw-r--r--tests/codegen/iter-repeat-n-trivial-drop.rs56
-rw-r--r--tests/codegen/layout-size-checks.rs31
-rw-r--r--tests/codegen/lifetime_start_end.rs34
-rw-r--r--tests/codegen/link-dead-code.rs22
-rw-r--r--tests/codegen/link_section.rs35
-rw-r--r--tests/codegen/loads.rs152
-rw-r--r--tests/codegen/local-generics-in-exe-internalized.rs14
-rw-r--r--tests/codegen/lto-removes-invokes.rs21
-rw-r--r--tests/codegen/mainsubprogram.rs13
-rw-r--r--tests/codegen/mainsubprogramstart.rs14
-rw-r--r--tests/codegen/match-optimized.rs60
-rw-r--r--tests/codegen/match-optimizes-away.rs34
-rw-r--r--tests/codegen/match-unoptimized.rs23
-rw-r--r--tests/codegen/mem-replace-direct-memcpy.rs24
-rw-r--r--tests/codegen/merge-functions.rs17
-rw-r--r--tests/codegen/mir-inlined-line-numbers.rs25
-rw-r--r--tests/codegen/mir_zst_stores.rs17
-rw-r--r--tests/codegen/move-operands.rs12
-rw-r--r--tests/codegen/naked-functions.rs32
-rw-r--r--tests/codegen/naked-nocoverage.rs19
-rw-r--r--tests/codegen/naked-noinline.rs31
-rw-r--r--tests/codegen/no-assumes-on-casts.rs19
-rw-r--r--tests/codegen/no-dllimport-w-cross-lang-lto.rs13
-rw-r--r--tests/codegen/no-jump-tables.rs22
-rw-r--r--tests/codegen/no-plt.rs17
-rw-r--r--tests/codegen/noalias-box-off.rs8
-rw-r--r--tests/codegen/noalias-box.rs8
-rw-r--r--tests/codegen/noalias-flag.rs23
-rw-r--r--tests/codegen/noalias-refcell.rs14
-rw-r--r--tests/codegen/noalias-rwlockreadguard.rs14
-rw-r--r--tests/codegen/noalias-unpin.rs15
-rw-r--r--tests/codegen/non-terminate/infinite-loop-1.rs17
-rw-r--r--tests/codegen/non-terminate/infinite-loop-2.rs19
-rw-r--r--tests/codegen/non-terminate/infinite-recursion.rs14
-rw-r--r--tests/codegen/non-terminate/nonempty-infinite-loop.rs28
-rw-r--r--tests/codegen/noreturn-uninhabited.rs31
-rw-r--r--tests/codegen/noreturnflag.rs22
-rw-r--r--tests/codegen/nounwind.rs16
-rw-r--r--tests/codegen/nrvo.rs17
-rw-r--r--tests/codegen/optimize-attr-1.rs50
-rw-r--r--tests/codegen/option-nonzero-eq.rs34
-rw-r--r--tests/codegen/packed.rs153
-rw-r--r--tests/codegen/panic-abort-windows.rs18
-rw-r--r--tests/codegen/panic-in-drop-abort.rs57
-rw-r--r--tests/codegen/panic-unwind-default-uwtable.rs6
-rw-r--r--tests/codegen/personality_lifetimes.rs32
-rw-r--r--tests/codegen/pgo-counter-bias.rs10
-rw-r--r--tests/codegen/pgo-instrumentation.rs22
-rw-r--r--tests/codegen/pic-relocation-model.rs19
-rw-r--r--tests/codegen/pie-relocation-model.rs22
-rw-r--r--tests/codegen/refs.rs23
-rw-r--r--tests/codegen/remap_path_prefix/aux_mod.rs6
-rw-r--r--tests/codegen/remap_path_prefix/auxiliary/remap_path_prefix_aux.rs8
-rw-r--r--tests/codegen/remap_path_prefix/auxiliary/xcrate-generic.rs6
-rw-r--r--tests/codegen/remap_path_prefix/issue-73167-remap-std.rs15
-rw-r--r--tests/codegen/remap_path_prefix/main.rs28
-rw-r--r--tests/codegen/remap_path_prefix/xcrate-generic.rs14
-rw-r--r--tests/codegen/repeat-trusted-len.rs20
-rw-r--r--tests/codegen/repr-transparent-aggregates-1.rs87
-rw-r--r--tests/codegen/repr-transparent-aggregates-2.rs90
-rw-r--r--tests/codegen/repr-transparent-aggregates-3.rs79
-rw-r--r--tests/codegen/repr-transparent-sysv64.rs28
-rw-r--r--tests/codegen/repr-transparent.rs170
-rw-r--r--tests/codegen/riscv-abi/call-llvm-intrinsics.rs30
-rw-r--r--tests/codegen/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs189
-rw-r--r--tests/codegen/riscv-abi/riscv64-lp64d-abi.rs293
-rw-r--r--tests/codegen/riscv-abi/riscv64-lp64f-lp64d-abi.rs277
-rw-r--r--tests/codegen/sanitizer-cfi-add-canonical-jump-tables-flag.rs11
-rw-r--r--tests/codegen/sanitizer-cfi-emit-type-checks.rs20
-rw-r--r--tests/codegen/sanitizer-cfi-emit-type-metadata-id-itanium-cxx-abi.rs591
-rw-r--r--tests/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi.rs31
-rw-r--r--tests/codegen/sanitizer-kcfi-add-kcfi-flag.rs11
-rw-r--r--tests/codegen/sanitizer-kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi.rs44
-rw-r--r--tests/codegen/sanitizer-memory-track-orgins.rs30
-rw-r--r--tests/codegen/sanitizer-no-sanitize-inlining.rs30
-rw-r--r--tests/codegen/sanitizer-no-sanitize.rs29
-rw-r--r--tests/codegen/sanitizer-recover.rs49
-rw-r--r--tests/codegen/sanitizer_memtag_attr_check.rs12
-rw-r--r--tests/codegen/sanitizer_scs_attr_check.rs17
-rw-r--r--tests/codegen/scalar-pair-bool.rs45
-rw-r--r--tests/codegen/set-discriminant-invalid.rs43
-rw-r--r--tests/codegen/simd-intrinsic/simd-intrinsic-float-abs.rs92
-rw-r--r--tests/codegen/simd-intrinsic/simd-intrinsic-float-ceil.rs92
-rw-r--r--tests/codegen/simd-intrinsic/simd-intrinsic-float-cos.rs92
-rw-r--r--tests/codegen/simd-intrinsic/simd-intrinsic-float-exp.rs92
-rw-r--r--tests/codegen/simd-intrinsic/simd-intrinsic-float-exp2.rs92
-rw-r--r--tests/codegen/simd-intrinsic/simd-intrinsic-float-floor.rs92
-rw-r--r--tests/codegen/simd-intrinsic/simd-intrinsic-float-fma.rs92
-rw-r--r--tests/codegen/simd-intrinsic/simd-intrinsic-float-fsqrt.rs92
-rw-r--r--tests/codegen/simd-intrinsic/simd-intrinsic-float-log.rs92
-rw-r--r--tests/codegen/simd-intrinsic/simd-intrinsic-float-log10.rs92
-rw-r--r--tests/codegen/simd-intrinsic/simd-intrinsic-float-log2.rs92
-rw-r--r--tests/codegen/simd-intrinsic/simd-intrinsic-float-minmax.rs29
-rw-r--r--tests/codegen/simd-intrinsic/simd-intrinsic-float-pow.rs92
-rw-r--r--tests/codegen/simd-intrinsic/simd-intrinsic-float-powi.rs92
-rw-r--r--tests/codegen/simd-intrinsic/simd-intrinsic-float-sin.rs92
-rw-r--r--tests/codegen/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.rs692
-rw-r--r--tests/codegen/simd-intrinsic/simd-intrinsic-generic-bitmask.rs63
-rw-r--r--tests/codegen/simd-intrinsic/simd-intrinsic-generic-extract-insert.rs47
-rw-r--r--tests/codegen/simd-intrinsic/simd-intrinsic-generic-gather.rs36
-rw-r--r--tests/codegen/simd-intrinsic/simd-intrinsic-generic-scatter.rs37
-rw-r--r--tests/codegen/simd-intrinsic/simd-intrinsic-generic-select.rs37
-rw-r--r--tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs43
-rw-r--r--tests/codegen/simd-wide-sum.rs55
-rw-r--r--tests/codegen/simd_arith_offset.rs26
-rw-r--r--tests/codegen/slice-as_chunks.rs33
-rw-r--r--tests/codegen/slice-init.rs64
-rw-r--r--tests/codegen/slice-iter-len-eq-zero.rs28
-rw-r--r--tests/codegen/slice-position-bounds-check.rs32
-rw-r--r--tests/codegen/slice-ref-equality.rs38
-rw-r--r--tests/codegen/slice-reverse.rs27
-rw-r--r--tests/codegen/slice-windows-no-bounds-check.rs35
-rw-r--r--tests/codegen/slice_as_from_ptr_range.rs23
-rw-r--r--tests/codegen/some-abis-do-extend-params-to-32-bits.rs204
-rw-r--r--tests/codegen/some-global-nonnull.rs25
-rw-r--r--tests/codegen/sparc-struct-abi.rs103
-rw-r--r--tests/codegen/src-hash-algorithm/src-hash-algorithm-md5.rs6
-rw-r--r--tests/codegen/src-hash-algorithm/src-hash-algorithm-sha1.rs6
-rw-r--r--tests/codegen/src-hash-algorithm/src-hash-algorithm-sha256.rs6
-rw-r--r--tests/codegen/sse42-implies-crc32.rs16
-rw-r--r--tests/codegen/stack-probes-call.rs24
-rw-r--r--tests/codegen/stack-probes-inline.rs32
-rw-r--r--tests/codegen/stack-protector.rs34
-rw-r--r--tests/codegen/static-relocation-model-msvc.rs26
-rw-r--r--tests/codegen/staticlib-external-inline-fns.rs43
-rw-r--r--tests/codegen/stores.rs35
-rw-r--r--tests/codegen/swap-large-types.rs91
-rw-r--r--tests/codegen/swap-simd-types.rs32
-rw-r--r--tests/codegen/swap-small-types.rs63
-rw-r--r--tests/codegen/target-cpu-on-functions.rs21
-rw-r--r--tests/codegen/target-feature-overrides.rs47
-rw-r--r--tests/codegen/thread-local.rs49
-rw-r--r--tests/codegen/to_vec.rs10
-rw-r--r--tests/codegen/transmute-scalar.rs81
-rw-r--r--tests/codegen/try_identity.rs34
-rw-r--r--tests/codegen/try_question_mark_nop.rs54
-rw-r--r--tests/codegen/tune-cpu-on-functions.rs21
-rw-r--r--tests/codegen/tuple-layout-opt.rs36
-rw-r--r--tests/codegen/unchecked-float-casts.rs36
-rw-r--r--tests/codegen/unchecked_shifts.rs66
-rw-r--r--tests/codegen/uninit-consts.rs55
-rw-r--r--tests/codegen/union-abi.rs76
-rw-r--r--tests/codegen/unpadded-simd.rs14
-rw-r--r--tests/codegen/unwind-abis/aapcs-unwind-abi.rs31
-rw-r--r--tests/codegen/unwind-abis/c-unwind-abi-panic-abort.rs28
-rw-r--r--tests/codegen/unwind-abis/c-unwind-abi.rs29
-rw-r--r--tests/codegen/unwind-abis/cdecl-unwind-abi.rs29
-rw-r--r--tests/codegen/unwind-abis/fastcall-unwind-abi.rs31
-rw-r--r--tests/codegen/unwind-abis/nounwind-on-stable-panic-abort.rs16
-rw-r--r--tests/codegen/unwind-abis/nounwind-on-stable-panic-unwind.rs17
-rw-r--r--tests/codegen/unwind-abis/nounwind.rs17
-rw-r--r--tests/codegen/unwind-abis/stdcall-unwind-abi.rs31
-rw-r--r--tests/codegen/unwind-abis/system-unwind-abi.rs29
-rw-r--r--tests/codegen/unwind-abis/sysv64-unwind-abi.rs31
-rw-r--r--tests/codegen/unwind-abis/thiscall-unwind-abi.rs31
-rw-r--r--tests/codegen/unwind-abis/vectorcall-unwind-abi.rs31
-rw-r--r--tests/codegen/unwind-abis/win64-unwind-abi.rs31
-rw-r--r--tests/codegen/unwind-and-panic-abort.rs17
-rw-r--r--tests/codegen/unwind-extern-exports.rs16
-rw-r--r--tests/codegen/unwind-extern-imports.rs22
-rw-r--r--tests/codegen/used_with_arg.rs10
-rw-r--r--tests/codegen/var-names.rs15
-rw-r--r--tests/codegen/vec-calloc-llvm14.rs144
-rw-r--r--tests/codegen/vec-calloc.rs184
-rw-r--r--tests/codegen/vec-in-place.rs74
-rw-r--r--tests/codegen/vec-iter-collect-len.rs12
-rw-r--r--tests/codegen/vec-optimizes-away.rs12
-rw-r--r--tests/codegen/vec-shrink-panik.rs47
-rw-r--r--tests/codegen/vecdeque_no_panic.rs19
-rw-r--r--tests/codegen/virtual-function-elimination-32bit.rs35
-rw-r--r--tests/codegen/virtual-function-elimination.rs100
-rw-r--r--tests/codegen/wasm_casts_trapping.rs157
-rw-r--r--tests/codegen/x86_64-macosx-deployment-target.rs27
-rw-r--r--tests/codegen/x86_64-no-macosx-deployment-target.rs27
-rw-r--r--tests/codegen/zip.rs21
-rw-r--r--tests/codegen/zst-offset.rs43
345 files changed, 14665 insertions, 0 deletions
diff --git a/tests/codegen/README.md b/tests/codegen/README.md
new file mode 100644
index 000000000..8f2daaafc
--- /dev/null
+++ b/tests/codegen/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/abi-efiapi.rs b/tests/codegen/abi-efiapi.rs
new file mode 100644
index 000000000..9502ebf59
--- /dev/null
+++ b/tests/codegen/abi-efiapi.rs
@@ -0,0 +1,33 @@
+// Checks if the correct annotation for the efiapi ABI is passed to llvm.
+
+// 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]
+
+#[lang="sized"]
+trait Sized { }
+#[lang="freeze"]
+trait Freeze { }
+#[lang="copy"]
+trait Copy { }
+
+//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/abi-main-signature-16bit-c-int.rs b/tests/codegen/abi-main-signature-16bit-c-int.rs
new file mode 100644
index 000000000..4ed491dfb
--- /dev/null
+++ b/tests/codegen/abi-main-signature-16bit-c-int.rs
@@ -0,0 +1,25 @@
+// 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.
+// ignore-aarch64
+// ignore-arm
+// ignore-asmjs
+// ignore-hexagon
+// ignore-mips
+// ignore-mips64
+// ignore-powerpc
+// ignore-powerpc64
+// ignore-riscv64
+// ignore-s390x
+// ignore-sparc
+// ignore-sparc64
+// ignore-wasm32
+// ignore-x86
+// ignore-x86_64
+// ignore-xcore
+
+fn main() {
+}
+
+// CHECK: define i16 @main(i16, i8**)
diff --git a/tests/codegen/abi-main-signature-32bit-c-int.rs b/tests/codegen/abi-main-signature-32bit-c-int.rs
new file mode 100644
index 000000000..7f22ddcfc
--- /dev/null
+++ b/tests/codegen/abi-main-signature-32bit-c-int.rs
@@ -0,0 +1,10 @@
+// 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
+
+fn main() {
+}
+
+// CHECK: define{{( hidden)?}} i32 @main(i32{{( %0)?}}, {{i8\*\*|ptr}}{{( %1)?}})
diff --git a/tests/codegen/abi-repr-ext.rs b/tests/codegen/abi-repr-ext.rs
new file mode 100644
index 000000000..23ade3c72
--- /dev/null
+++ b/tests/codegen/abi-repr-ext.rs
@@ -0,0 +1,57 @@
+// compile-flags: -O
+
+// 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]
+
+#[lang="sized"] trait Sized { }
+#[lang="freeze"] trait Freeze { }
+#[lang="copy"] trait Copy { }
+
+#[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/abi-sysv64.rs b/tests/codegen/abi-sysv64.rs
new file mode 100644
index 000000000..3c2d4e719
--- /dev/null
+++ b/tests/codegen/abi-sysv64.rs
@@ -0,0 +1,22 @@
+// 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.
+//
+// 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)]
+
+#[lang = "sized"]
+trait Sized {}
+#[lang = "copy"]
+trait Copy {}
+impl Copy for i64 {}
+
+// 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/abi-x86-interrupt.rs b/tests/codegen/abi-x86-interrupt.rs
new file mode 100644
index 000000000..928ad5a9b
--- /dev/null
+++ b/tests/codegen/abi-x86-interrupt.rs
@@ -0,0 +1,22 @@
+// 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.
+
+// 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)]
+
+#[lang = "sized"]
+trait Sized {}
+#[lang = "copy"]
+trait Copy {}
+impl Copy for i64 {}
+
+// CHECK: define x86_intrcc i64 @has_x86_interrupt_abi
+#[no_mangle]
+pub extern "x86-interrupt" fn has_x86_interrupt_abi(a: i64) -> i64 {
+ a
+}
diff --git a/tests/codegen/abi-x86_64_sysv.rs b/tests/codegen/abi-x86_64_sysv.rs
new file mode 100644
index 000000000..84e06023e
--- /dev/null
+++ b/tests/codegen/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/adjustments.rs b/tests/codegen/adjustments.rs
new file mode 100644
index 000000000..6d2247517
--- /dev/null
+++ b/tests/codegen/adjustments.rs
@@ -0,0 +1,29 @@
+// 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 { {{\[0 x i8\]\*|ptr}}, [[USIZE]] } undef, {{\[0 x i8\]\*|ptr}} %x.0, 0
+// CHECK: %1 = insertvalue { {{\[0 x i8\]\*|ptr}}, [[USIZE]] } %0, [[USIZE]] %x.1, 1
+// CHECK: ret { {{\[0 x i8\]\*|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/align-enum.rs b/tests/codegen/align-enum.rs
new file mode 100644
index 000000000..70f09ace0
--- /dev/null
+++ b/tests/codegen/align-enum.rs
@@ -0,0 +1,34 @@
+// compile-flags: -C no-prepopulate-passes -Z mir-opt-level=0
+//
+
+#![crate_type = "lib"]
+
+#[repr(align(64))]
+pub enum Align64 {
+ A(u32),
+ B(u32),
+}
+// CHECK: %Align64 = type { i32, [15 x i32] }
+
+pub struct Nested64 {
+ a: u8,
+ b: Align64,
+ c: u16,
+}
+
+// CHECK-LABEL: @align64
+#[no_mangle]
+pub fn align64(a: u32) -> Align64 {
+// CHECK: %a64 = alloca %Align64, align 64
+// CHECK: call void @llvm.memcpy.{{.*}}({{i8\*|ptr}} align 64 %{{.*}}, {{i8\*|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 %Nested64, align 64
+ let n64 = Nested64 { a, b: Align64::B(b), c };
+ n64
+}
diff --git a/tests/codegen/align-fn.rs b/tests/codegen/align-fn.rs
new file mode 100644
index 000000000..c5886cf28
--- /dev/null
+++ b/tests/codegen/align-fn.rs
@@ -0,0 +1,9 @@
+// compile-flags: -C no-prepopulate-passes -Z mir-opt-level=0
+
+#![crate_type = "lib"]
+#![feature(fn_align)]
+
+// CHECK: align 16
+#[no_mangle]
+#[repr(align(16))]
+pub fn fn_align() {}
diff --git a/tests/codegen/align-struct.rs b/tests/codegen/align-struct.rs
new file mode 100644
index 000000000..a2f47354b
--- /dev/null
+++ b/tests/codegen/align-struct.rs
@@ -0,0 +1,71 @@
+// compile-flags: -C no-prepopulate-passes -Z mir-opt-level=0
+//
+
+#![crate_type = "lib"]
+
+#[repr(align(64))]
+pub struct Align64(i32);
+// CHECK: %Align64 = type { i32, [15 x i32] }
+
+pub struct Nested64 {
+ a: Align64,
+ b: i32,
+ c: i32,
+ d: i8,
+}
+// CHECK: %Nested64 = type { %Align64, i32, i32, i8, [55 x i8] }
+
+pub enum Enum4 {
+ A(i32),
+ B(i32),
+}
+// No Aggregate type, and hence nothing in LLVM IR.
+
+pub enum Enum64 {
+ A(Align64),
+ B(i32),
+}
+// CHECK: %Enum64 = type { i32, [31 x i32] }
+// CHECK: %"Enum64::A" = type { [8 x i64], %Align64 }
+
+// CHECK-LABEL: @align64
+#[no_mangle]
+pub fn align64(i : i32) -> Align64 {
+// CHECK: %a64 = alloca %Align64, align 64
+// CHECK: call void @llvm.memcpy.{{.*}}({{i8\*|ptr}} align 64 %{{.*}}, {{i8\*|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, {{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 %Nested64, align 64
+ let n64 = Nested64 { a, b, c, d };
+ n64
+}
+
+// CHECK-LABEL: @enum4
+#[no_mangle]
+pub fn enum4(a: i32) -> Enum4 {
+// CHECK: %e4 = alloca { i32, i32 }, align 4
+ let e4 = Enum4::A(a);
+ e4
+}
+
+// CHECK-LABEL: @enum64
+#[no_mangle]
+pub fn enum64(a: Align64) -> Enum64 {
+// CHECK: %e64 = alloca %Enum64, align 64
+ let e64 = Enum64::A(a);
+ e64
+}
diff --git a/tests/codegen/alloc-optimisation.rs b/tests/codegen/alloc-optimisation.rs
new file mode 100644
index 000000000..c3ffaeb95
--- /dev/null
+++ b/tests/codegen/alloc-optimisation.rs
@@ -0,0 +1,13 @@
+//
+// no-system-llvm
+// compile-flags: -O
+#![crate_type="lib"]
+
+#[no_mangle]
+pub fn alloc_test(data: u32) {
+ // CHECK-LABEL: @alloc_test
+ // CHECK-NEXT: start:
+ // CHECK-NEXT: ret void
+ let x = Box::new(data);
+ drop(x);
+}
diff --git a/tests/codegen/array-clone.rs b/tests/codegen/array-clone.rs
new file mode 100644
index 000000000..0d42963bc
--- /dev/null
+++ b/tests/codegen/array-clone.rs
@@ -0,0 +1,15 @@
+// compile-flags: -O
+
+#![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/array-equality.rs b/tests/codegen/array-equality.rs
new file mode 100644
index 000000000..cd5e82a92
--- /dev/null
+++ b/tests/codegen/array-equality.rs
@@ -0,0 +1,74 @@
+// compile-flags: -O
+// 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, {{i48\*|ptr}} %{{.+}}, align 2
+ // CHECK: load i48, {{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}}({{i8\*|ptr}} {{.*}} dereferenceable(18) %{{.+}}, {{i8\*|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}}({{i8\*|ptr}} {{.*}} dereferenceable(2468) %{{.+}}, {{i8\*|ptr}} {{.*}} dereferenceable(2468) %{{.+}}, i64 2468)
+ // CHECK-NEXT: %[[EQ:.+]] = icmp eq i32 %[[CMP]], 0
+ // 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_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/asm-clobber_abi.rs b/tests/codegen/asm-clobber_abi.rs
new file mode 100644
index 000000000..f70caea2f
--- /dev/null
+++ b/tests/codegen/asm-clobber_abi.rs
@@ -0,0 +1,36 @@
+// compile-flags: -O
+// 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/asm-clobbers.rs b/tests/codegen/asm-clobbers.rs
new file mode 100644
index 000000000..2ef10a283
--- /dev/null
+++ b/tests/codegen/asm-clobbers.rs
@@ -0,0 +1,20 @@
+// compile-flags: -O
+// 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/asm-may_unwind.rs b/tests/codegen/asm-may_unwind.rs
new file mode 100644
index 000000000..c97933035
--- /dev/null
+++ b/tests/codegen/asm-may_unwind.rs
@@ -0,0 +1,39 @@
+// compile-flags: -O
+// 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/asm-multiple-options.rs b/tests/codegen/asm-multiple-options.rs
new file mode 100644
index 000000000..1ae37d627
--- /dev/null
+++ b/tests/codegen/asm-multiple-options.rs
@@ -0,0 +1,54 @@
+// compile-flags: -O
+// 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/asm-options.rs b/tests/codegen/asm-options.rs
new file mode 100644
index 000000000..963b60cfe
--- /dev/null
+++ b/tests/codegen/asm-options.rs
@@ -0,0 +1,104 @@
+// compile-flags: -O
+// 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/asm-powerpc-clobbers.rs b/tests/codegen/asm-powerpc-clobbers.rs
new file mode 100644
index 000000000..10b20ba6b
--- /dev/null
+++ b/tests/codegen/asm-powerpc-clobbers.rs
@@ -0,0 +1,47 @@
+// revisions: powerpc powerpc64 powerpc64le
+//[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
+
+#![crate_type = "rlib"]
+#![feature(no_core, rustc_attrs, lang_items, asm_experimental_arch)]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+
+#[rustc_builtin_macro]
+macro_rules! asm {
+ () => {};
+}
+
+// CHECK-LABEL: @cr_clobber
+// CHECK: call void asm sideeffect "", "~{cr}"()
+#[no_mangle]
+pub unsafe fn cr_clobber() {
+ asm!("", out("cr") _, options(nostack, nomem));
+}
+
+// CHECK-LABEL: @cr0_clobber
+// CHECK: call void asm sideeffect "", "~{cr0}"()
+#[no_mangle]
+pub unsafe fn cr0_clobber() {
+ asm!("", out("cr0") _, options(nostack, nomem));
+}
+
+// CHECK-LABEL: @cr5_clobber
+// CHECK: call void asm sideeffect "", "~{cr5}"()
+#[no_mangle]
+pub unsafe fn cr5_clobber() {
+ asm!("", out("cr5") _, options(nostack, nomem));
+}
+
+// CHECK-LABEL: @xer_clobber
+// CHECK: call void asm sideeffect "", "~{xer}"()
+#[no_mangle]
+pub unsafe fn xer_clobber() {
+ asm!("", out("xer") _, options(nostack, nomem));
+}
diff --git a/tests/codegen/asm-sanitize-llvm.rs b/tests/codegen/asm-sanitize-llvm.rs
new file mode 100644
index 000000000..6dcacd08c
--- /dev/null
+++ b/tests/codegen/asm-sanitize-llvm.rs
@@ -0,0 +1,34 @@
+// FIXME(nagisa): remove the flags below once all targets support `asm!`.
+// compile-flags: --target x86_64-unknown-linux-gnu
+// 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, lang_items, rustc_attrs)]
+#![crate_type = "rlib"]
+#![allow(named_asm_labels)]
+
+#[rustc_builtin_macro]
+macro_rules! asm {
+ () => {};
+}
+
+#[lang = "sized"]
+trait Sized {}
+#[lang = "copy"]
+trait Copy {}
+
+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/asm-target-clobbers.rs b/tests/codegen/asm-target-clobbers.rs
new file mode 100644
index 000000000..ac30e18ec
--- /dev/null
+++ b/tests/codegen/asm-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/async-fn-debug-awaitee-field.rs b/tests/codegen/async-fn-debug-awaitee-field.rs
new file mode 100644
index 000000000..bc2686158
--- /dev/null
+++ b/tests/codegen/async-fn-debug-awaitee-field.rs
@@ -0,0 +1,25 @@
+// This test makes sure that the generator 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.
+
+// ignore-tidy-linelength
+// compile-flags: -C debuginfo=2 --edition=2018
+
+async fn foo() {}
+
+async fn async_fn_test() {
+ foo().await;
+}
+
+// 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",
+
+fn main() {
+ let _fn = async_fn_test();
+}
diff --git a/tests/codegen/async-fn-debug-msvc.rs b/tests/codegen/async-fn-debug-msvc.rs
new file mode 100644
index 000000000..73c652c9d
--- /dev/null
+++ b/tests/codegen/async-fn-debug-msvc.rs
@@ -0,0 +1,54 @@
+// Verify debuginfo for generators:
+// - 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: 11,
+// CHECK-NOT: flags: DIFlagArtificial
+// CHECK-SAME: )
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant1", scope: [[GEN]],
+// CHECK-SAME: file: [[FILE]], line: 15,
+// CHECK-NOT: flags: DIFlagArtificial
+// CHECK-SAME: )
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant2", scope: [[GEN]],
+// CHECK-SAME: file: [[FILE]], line: 15,
+// CHECK-NOT: flags: DIFlagArtificial
+// CHECK-SAME: )
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant3", scope: [[GEN]],
+// CHECK-SAME: file: [[FILE]], line: 12,
+// CHECK-NOT: flags: DIFlagArtificial
+// CHECK-SAME: )
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant4", scope: [[GEN]],
+// CHECK-SAME: file: [[FILE]], line: 14,
+// 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/async-fn-debug.rs b/tests/codegen/async-fn-debug.rs
new file mode 100644
index 000000000..9f6058a71
--- /dev/null
+++ b/tests/codegen/async-fn-debug.rs
@@ -0,0 +1,58 @@
+// 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: 11,
+// 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: 15,
+// CHECK-NOT: flags: DIFlagArtificial
+// CHECK-SAME: )
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "2", scope: [[VARIANT]],
+// CHECK-SAME: file: [[FILE]], line: 15,
+// CHECK-NOT: flags: DIFlagArtificial
+// CHECK-SAME: )
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "3", scope: [[VARIANT]],
+// CHECK-SAME: file: [[FILE]], line: 12,
+// CHECK-NOT: flags: DIFlagArtificial
+// CHECK-SAME: )
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "4", scope: [[VARIANT]],
+// CHECK-SAME: file: [[FILE]], line: 14,
+// 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/atomic-operations.rs b/tests/codegen/atomic-operations.rs
new file mode 100644
index 000000000..d2bc618df
--- /dev/null
+++ b/tests/codegen/atomic-operations.rs
@@ -0,0 +1,83 @@
+// Code generation of atomic operations.
+// compile-flags: -O
+#![crate_type = "lib"]
+
+use std::sync::atomic::{AtomicI32, Ordering::*};
+
+// CHECK-LABEL: @compare_exchange
+#[no_mangle]
+pub fn compare_exchange(a: &AtomicI32) {
+ // CHECK: cmpxchg {{i32\*|ptr}} %{{.*}}, i32 0, i32 10 monotonic monotonic
+ // CHECK: cmpxchg {{i32\*|ptr}} %{{.*}}, i32 0, i32 11 monotonic acquire
+ // CHECK: cmpxchg {{i32\*|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 {{i32\*|ptr}} %{{.*}}, i32 0, i32 20 release monotonic
+ // CHECK: cmpxchg {{i32\*|ptr}} %{{.*}}, i32 0, i32 21 release acquire
+ // CHECK: cmpxchg {{i32\*|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 {{i32\*|ptr}} %{{.*}}, i32 0, i32 30 acquire monotonic
+ // CHECK: cmpxchg {{i32\*|ptr}} %{{.*}}, i32 0, i32 31 acquire acquire
+ // CHECK: cmpxchg {{i32\*|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 {{i32\*|ptr}} %{{.*}}, i32 0, i32 40 acq_rel monotonic
+ // CHECK: cmpxchg {{i32\*|ptr}} %{{.*}}, i32 0, i32 41 acq_rel acquire
+ // CHECK: cmpxchg {{i32\*|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 {{i32\*|ptr}} %{{.*}}, i32 0, i32 50 seq_cst monotonic
+ // CHECK: cmpxchg {{i32\*|ptr}} %{{.*}}, i32 0, i32 51 seq_cst acquire
+ // CHECK: cmpxchg {{i32\*|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 {{i32\*|ptr}} %{{.*}}, i32 1, i32 10 monotonic monotonic
+ // CHECK: cmpxchg weak {{i32\*|ptr}} %{{.*}}, i32 1, i32 11 monotonic acquire
+ // CHECK: cmpxchg weak {{i32\*|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 {{i32\*|ptr}} %{{.*}}, i32 1, i32 20 release monotonic
+ // CHECK: cmpxchg weak {{i32\*|ptr}} %{{.*}}, i32 1, i32 21 release acquire
+ // CHECK: cmpxchg weak {{i32\*|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 {{i32\*|ptr}} %{{.*}}, i32 1, i32 30 acquire monotonic
+ // CHECK: cmpxchg weak {{i32\*|ptr}} %{{.*}}, i32 1, i32 31 acquire acquire
+ // CHECK: cmpxchg weak {{i32\*|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 {{i32\*|ptr}} %{{.*}}, i32 1, i32 40 acq_rel monotonic
+ // CHECK: cmpxchg weak {{i32\*|ptr}} %{{.*}}, i32 1, i32 41 acq_rel acquire
+ // CHECK: cmpxchg weak {{i32\*|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 {{i32\*|ptr}} %{{.*}}, i32 1, i32 50 seq_cst monotonic
+ // CHECK: cmpxchg weak {{i32\*|ptr}} %{{.*}}, i32 1, i32 51 seq_cst acquire
+ // CHECK: cmpxchg weak {{i32\*|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/autovectorize-f32x4.rs b/tests/codegen/autovectorize-f32x4.rs
new file mode 100644
index 000000000..6b09c8fc9
--- /dev/null
+++ b/tests/codegen/autovectorize-f32x4.rs
@@ -0,0 +1,32 @@
+// compile-flags: -C opt-level=3
+// 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
+}
diff --git a/tests/codegen/auxiliary/extern_decl.rs b/tests/codegen/auxiliary/extern_decl.rs
new file mode 100644
index 000000000..edc483518
--- /dev/null
+++ b/tests/codegen/auxiliary/extern_decl.rs
@@ -0,0 +1,11 @@
+// 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/auxiliary/nounwind.rs b/tests/codegen/auxiliary/nounwind.rs
new file mode 100644
index 000000000..73c5aee33
--- /dev/null
+++ b/tests/codegen/auxiliary/nounwind.rs
@@ -0,0 +1,3 @@
+#[no_mangle]
+pub fn bar() {
+}
diff --git a/tests/codegen/auxiliary/static_dllimport_aux.rs b/tests/codegen/auxiliary/static_dllimport_aux.rs
new file mode 100644
index 000000000..afb0dc42f
--- /dev/null
+++ b/tests/codegen/auxiliary/static_dllimport_aux.rs
@@ -0,0 +1,13 @@
+use std::sync::atomic::{AtomicPtr, Ordering};
+
+#[inline(always)]
+pub fn memrchr() {
+ fn detect() {}
+
+ static CROSS_CRATE_STATIC_ITEM: AtomicPtr<()> = AtomicPtr::new(detect as *mut ());
+
+ unsafe {
+ let fun = CROSS_CRATE_STATIC_ITEM.load(Ordering::SeqCst);
+ std::mem::transmute::<*mut (), fn()>(fun)()
+ }
+}
diff --git a/tests/codegen/auxiliary/thread_local_aux.rs b/tests/codegen/auxiliary/thread_local_aux.rs
new file mode 100644
index 000000000..bebaa7754
--- /dev/null
+++ b/tests/codegen/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/avr/avr-func-addrspace.rs b/tests/codegen/avr/avr-func-addrspace.rs
new file mode 100644
index 000000000..e9740e30d
--- /dev/null
+++ b/tests/codegen/avr/avr-func-addrspace.rs
@@ -0,0 +1,111 @@
+// compile-flags: -O --target=avr-unknown-gnu-atmega328 --crate-type=rlib
+// 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]
+
+#[lang = "sized"]
+pub trait Sized { }
+#[lang = "copy"]
+pub trait Copy { }
+#[lang = "receiver"]
+pub trait Receiver { }
+#[lang = "tuple_trait"]
+pub trait Tuple { }
+
+pub struct Result<T, E> { _a: T, _b: E }
+
+impl Copy for usize {}
+impl Copy for &usize {}
+
+#[lang = "drop_in_place"]
+pub unsafe fn drop_in_place<T: ?Sized>(_: *mut T) {}
+
+#[lang = "fn_once"]
+pub trait FnOnce<Args: Tuple> {
+ #[lang = "fn_once_output"]
+ type Output;
+
+ extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
+}
+
+#[lang = "fn_mut"]
+pub trait FnMut<Args: Tuple> : FnOnce<Args> {
+ extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
+}
+
+#[lang = "fn"]
+pub trait Fn<Args: Tuple>: FnOnce<Args> {
+ /// Performs the call operation.
+ extern "rust-call" fn call(&self, args: Args) -> Self::Output;
+}
+
+extern "rust-intrinsic" {
+ pub 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{{.+}}{{void \(\) addrspace\(1\)\*|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({{void \(\) addrspace\(1\)\*|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)
+}
diff --git a/tests/codegen/binary-search-index-no-bound-check.rs b/tests/codegen/binary-search-index-no-bound-check.rs
new file mode 100644
index 000000000..c1766a4a4
--- /dev/null
+++ b/tests/codegen/binary-search-index-no-bound-check.rs
@@ -0,0 +1,38 @@
+// compile-flags: -O
+// ignore-debug: the debug assertions get in the way
+#![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_index_len_fail
+ 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/bool-cmp.rs b/tests/codegen/bool-cmp.rs
new file mode 100644
index 000000000..5090f7c37
--- /dev/null
+++ b/tests/codegen/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/box-maybe-uninit-llvm14.rs b/tests/codegen/box-maybe-uninit-llvm14.rs
new file mode 100644
index 000000000..b0c88f76c
--- /dev/null
+++ b/tests/codegen/box-maybe-uninit-llvm14.rs
@@ -0,0 +1,34 @@
+// compile-flags: -O
+
+// Once we're done with llvm 14 and earlier, this test can be deleted.
+
+#![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())
+}
+
+// Hide the LLVM 15+ `allocalign` attribute in the declaration of __rust_alloc
+// from the CHECK-NOT above. We don't check the attributes here because we can't rely
+// on all of them being set until LLVM 15.
+// CHECK: declare noalias{{.*}} @__rust_alloc(i{{[0-9]+}} noundef, i{{[0-9]+.*}} noundef)
diff --git a/tests/codegen/box-maybe-uninit.rs b/tests/codegen/box-maybe-uninit.rs
new file mode 100644
index 000000000..2f8896699
--- /dev/null
+++ b/tests/codegen/box-maybe-uninit.rs
@@ -0,0 +1,33 @@
+// compile-flags: -O
+// min-llvm-version: 15.0
+#![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())
+}
+
+// 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 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/bpf-alu32.rs b/tests/codegen/bpf-alu32.rs
new file mode 100644
index 000000000..c68bffd03
--- /dev/null
+++ b/tests/codegen/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/branch-protection.rs b/tests/codegen/branch-protection.rs
new file mode 100644
index 000000000..994c71b26
--- /dev/null
+++ b/tests/codegen/branch-protection.rs
@@ -0,0 +1,45 @@
+// Test that the correct module flags are emitted with different branch protection flags.
+
+// revisions: BTI PACRET LEAF BKEY 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
+// compile-flags: --target aarch64-unknown-linux-gnu
+
+#![crate_type = "lib"]
+#![feature(no_core, lang_items)]
+#![no_core]
+
+#[lang="sized"]
+trait Sized { }
+
+// A basic test function.
+pub fn test() {
+}
+
+// BTI: !"branch-target-enforcement", i32 1
+// BTI: !"sign-return-address", i32 0
+// BTI: !"sign-return-address-all", i32 0
+// BTI: !"sign-return-address-with-bkey", i32 0
+
+// PACRET: !"branch-target-enforcement", i32 0
+// PACRET: !"sign-return-address", i32 1
+// PACRET: !"sign-return-address-all", i32 0
+// PACRET: !"sign-return-address-with-bkey", i32 0
+
+// LEAF: !"branch-target-enforcement", i32 0
+// LEAF: !"sign-return-address", i32 1
+// LEAF: !"sign-return-address-all", i32 1
+// LEAF: !"sign-return-address-with-bkey", i32 0
+
+// BKEY: !"branch-target-enforcement", i32 0
+// BKEY: !"sign-return-address", i32 1
+// BKEY: !"sign-return-address-all", i32 0
+// BKEY: !"sign-return-address-with-bkey", i32 1
+
+// 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/c-variadic-copy.rs b/tests/codegen/c-variadic-copy.rs
new file mode 100644
index 000000000..4c61c4fcf
--- /dev/null
+++ b/tests/codegen/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/c-variadic-opt.rs b/tests/codegen/c-variadic-opt.rs
new file mode 100644
index 000000000..969dce80f
--- /dev/null
+++ b/tests/codegen/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/c-variadic.rs b/tests/codegen/c-variadic.rs
new file mode 100644
index 000000000..cab326522
--- /dev/null
+++ b/tests/codegen/c-variadic.rs
@@ -0,0 +1,72 @@
+// ignore-wasm32-bare compiled with panic=abort by default
+// compile-flags: -C no-prepopulate-passes -Copt-level=0
+//
+
+#![crate_type = "lib"]
+#![feature(c_variadic)]
+#![feature(c_unwind)]
+#![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/call-llvm-intrinsics.rs b/tests/codegen/call-llvm-intrinsics.rs
new file mode 100644
index 000000000..cb8abae19
--- /dev/null
+++ b/tests/codegen/call-llvm-intrinsics.rs
@@ -0,0 +1,29 @@
+// compile-flags: -C no-prepopulate-passes -Copt-level=0
+
+// ignore-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: call float @llvm.sqrt.f32(float 4.000000e+00
+ sqrt(4.0);
+ }
+}
diff --git a/tests/codegen/call-metadata.rs b/tests/codegen/call-metadata.rs
new file mode 100644
index 000000000..1c30c08d3
--- /dev/null
+++ b/tests/codegen/call-metadata.rs
@@ -0,0 +1,17 @@
+// Checks that range metadata gets emitted on calls to functions returning a
+// scalar value.
+
+// compile-flags: -O -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+pub fn test() {
+ // CHECK: call noundef i8 @some_true(), !range [[R0:![0-9]+]]
+ // CHECK: [[R0]] = !{i8 0, i8 3}
+ some_true();
+}
+
+#[no_mangle]
+fn some_true() -> Option<bool> {
+ Some(true)
+}
diff --git a/tests/codegen/catch-unwind.rs b/tests/codegen/catch-unwind.rs
new file mode 100644
index 000000000..b90ef104c
--- /dev/null
+++ b/tests/codegen/catch-unwind.rs
@@ -0,0 +1,31 @@
+// compile-flags: -O
+
+// 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
+
+#![crate_type = "lib"]
+#![feature(c_unwind)]
+
+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/cdylib-external-inline-fns.rs b/tests/codegen/cdylib-external-inline-fns.rs
new file mode 100644
index 000000000..9118afd43
--- /dev/null
+++ b/tests/codegen/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/cf-protection.rs b/tests/codegen/cf-protection.rs
new file mode 100644
index 000000000..ccbc863f5
--- /dev/null
+++ b/tests/codegen/cf-protection.rs
@@ -0,0 +1,38 @@
+// Test that the correct module flags are emitted with different control-flow protection flags.
+
+// 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]
+
+#[lang="sized"]
+trait Sized { }
+
+// 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/cfguard-checks.rs b/tests/codegen/cfguard-checks.rs
new file mode 100644
index 000000000..571a2654b
--- /dev/null
+++ b/tests/codegen/cfguard-checks.rs
@@ -0,0 +1,11 @@
+// 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/cfguard-disabled.rs b/tests/codegen/cfguard-disabled.rs
new file mode 100644
index 000000000..c3f8f4116
--- /dev/null
+++ b/tests/codegen/cfguard-disabled.rs
@@ -0,0 +1,11 @@
+// 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/cfguard-nochecks.rs b/tests/codegen/cfguard-nochecks.rs
new file mode 100644
index 000000000..3847c3e81
--- /dev/null
+++ b/tests/codegen/cfguard-nochecks.rs
@@ -0,0 +1,11 @@
+// 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/cfguard-non-msvc.rs b/tests/codegen/cfguard-non-msvc.rs
new file mode 100644
index 000000000..6278a951e
--- /dev/null
+++ b/tests/codegen/cfguard-non-msvc.rs
@@ -0,0 +1,11 @@
+// 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/codemodels.rs b/tests/codegen/codemodels.rs
new file mode 100644
index 000000000..2328f5feb
--- /dev/null
+++ b/tests/codegen/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/coercions.rs b/tests/codegen/coercions.rs
new file mode 100644
index 000000000..d645ca6b1
--- /dev/null
+++ b/tests/codegen/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/cold-call-declare-and-call.rs b/tests/codegen/cold-call-declare-and-call.rs
new file mode 100644
index 000000000..71d49478b
--- /dev/null
+++ b/tests/codegen/cold-call-declare-and-call.rs
@@ -0,0 +1,18 @@
+// compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+#![feature(rust_cold_cc)]
+
+// wasm marks the definition as `dso_local`, so allow that as optional.
+
+// CHECK: define{{( dso_local)?}} coldcc void @this_should_never_happen(i16
+// CHECK: call coldcc 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/comparison-operators-newtype.rs b/tests/codegen/comparison-operators-newtype.rs
new file mode 100644
index 000000000..683a2bd4f
--- /dev/null
+++ b/tests/codegen/comparison-operators-newtype.rs
@@ -0,0 +1,49 @@
+// 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
+// min-llvm-version: 15.0
+
+#![crate_type = "lib"]
+
+use std::cmp::Ordering;
+
+#[derive(PartialOrd, PartialEq)]
+pub struct Foo(u16);
+
+// CHECK-LABEL: @check_lt
+// CHECK-SAME: (i16 noundef %[[A:.+]], i16 noundef %[[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 noundef %[[A:.+]], i16 noundef %[[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 noundef %[[A:.+]], i16 noundef %[[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 noundef %[[A:.+]], i16 noundef %[[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/consts.rs b/tests/codegen/consts.rs
new file mode 100644
index 000000000..260d9de86
--- /dev/null
+++ b/tests/codegen/consts.rs
@@ -0,0 +1,56 @@
+// compile-flags: -C no-prepopulate-passes
+// min-llvm-version: 14.0
+
+#![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: @alloc12 = {{.*}}, 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[0-9]+]] = {{.*}}, 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.{{.+}}({{i8\*|ptr}} align 2 %{{[0-9]+}}, {{i8\*|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.{{.+}}({{i8\*|ptr}} align 4 %{{[0-9]+}}, {{i8\*|ptr}} align 4 {{.*}}[[LOW_HIGH]]{{.*}}, i{{(32|64)}} 8, i1 false)
+ *&E::A(0)
+}
diff --git a/tests/codegen/dealloc-no-unwind.rs b/tests/codegen/dealloc-no-unwind.rs
new file mode 100644
index 000000000..3812ef44f
--- /dev/null
+++ b/tests/codegen/dealloc-no-unwind.rs
@@ -0,0 +1,22 @@
+// no-system-llvm
+// compile-flags: -O
+
+#![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/debug-alignment.rs b/tests/codegen/debug-alignment.rs
new file mode 100644
index 000000000..f6c1062e0
--- /dev/null
+++ b/tests/codegen/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/debug-column-msvc.rs b/tests/codegen/debug-column-msvc.rs
new file mode 100644
index 000000000..aad8b372a
--- /dev/null
+++ b/tests/codegen/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/debug-column.rs b/tests/codegen/debug-column.rs
new file mode 100644
index 000000000..e61642b8e
--- /dev/null
+++ b/tests/codegen/debug-column.rs
@@ -0,0 +1,24 @@
+// Verify that debuginfo column numbers are 1-based byte offsets.
+//
+// ignore-windows
+// compile-flags: -C debuginfo=2
+
+fn main() {
+ unsafe {
+ // Column numbers are 1-based. Regression test for #65437.
+ // CHECK: call void @giraffe(), !dbg [[A:!.*]]
+ giraffe();
+
+ // Column numbers use byte offests. Regression test for #67360
+ // CHECK: call void @turtle(), !dbg [[B:!.*]]
+/* ż */ turtle();
+
+ // CHECK: [[A]] = !DILocation(line: 10, column: 9,
+ // CHECK: [[B]] = !DILocation(line: 14, column: 10,
+ }
+}
+
+extern "C" {
+ fn giraffe();
+ fn turtle();
+}
diff --git a/tests/codegen/debug-compile-unit-path.rs b/tests/codegen/debug-compile-unit-path.rs
new file mode 100644
index 000000000..3661be046
--- /dev/null
+++ b/tests/codegen/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/debug-linkage-name.rs b/tests/codegen/debug-linkage-name.rs
new file mode 100644
index 000000000..9011a7da5
--- /dev/null
+++ b/tests/codegen/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
+// compile-flags: -C debuginfo=2
+#![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/debug-vtable.rs b/tests/codegen/debug-vtable.rs
new file mode 100644
index 000000000..bdd312878
--- /dev/null
+++ b/tests/codegen/debug-vtable.rs
@@ -0,0 +1,107 @@
+// This test checks the debuginfo for the expected 3 vtables is generated for correct names and number
+// of entries.
+
+// 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
+// ignore-tidy-linelength
+
+// 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/debuginfo-generic-closure-env-names.rs b/tests/codegen/debuginfo-generic-closure-env-names.rs
new file mode 100644
index 000000000..b29f8b4a0
--- /dev/null
+++ b/tests/codegen/debuginfo-generic-closure-env-names.rs
@@ -0,0 +1,89 @@
+// 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.
+
+// ignore-tidy-linelength
+
+// 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 --edition 2021 -Copt-level=0 -Csymbol-mangling-version=v0
+
+// 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/deduced-param-attrs.rs b/tests/codegen/deduced-param-attrs.rs
new file mode 100644
index 000000000..153046eef
--- /dev/null
+++ b/tests/codegen/deduced-param-attrs.rs
@@ -0,0 +1,60 @@
+// compile-flags: -O
+
+#![crate_type = "lib"]
+#![allow(incomplete_features)]
+#![feature(unsized_locals, 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/default-requires-uwtable.rs b/tests/codegen/default-requires-uwtable.rs
new file mode 100644
index 000000000..5d77d3f14
--- /dev/null
+++ b/tests/codegen/default-requires-uwtable.rs
@@ -0,0 +1,16 @@
+// revisions: WINDOWS ANDROID
+// compile-flags: -C panic=abort
+// [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]
+
+#[lang = "sized"]
+trait Sized {}
+
+// CHECK: attributes #{{.*}} uwtable
+pub fn foo() {}
diff --git a/tests/codegen/dllimports/auxiliary/dummy.rs b/tests/codegen/dllimports/auxiliary/dummy.rs
new file mode 100644
index 000000000..113a164f1
--- /dev/null
+++ b/tests/codegen/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/dllimports/auxiliary/wrapper.rs b/tests/codegen/dllimports/auxiliary/wrapper.rs
new file mode 100644
index 000000000..7aa90920a
--- /dev/null
+++ b/tests/codegen/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/dllimports/main.rs b/tests/codegen/dllimports/main.rs
new file mode 100644
index 000000000..383940e95
--- /dev/null
+++ b/tests/codegen/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/drop.rs b/tests/codegen/drop.rs
new file mode 100644
index 000000000..994028271
--- /dev/null
+++ b/tests/codegen/drop.rs
@@ -0,0 +1,36 @@
+// ignore-wasm32-bare compiled with panic=abort by default
+// compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+struct SomeUniqueName;
+
+impl Drop for SomeUniqueName {
+ fn drop(&mut self) {
+ }
+}
+
+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/dst-vtable-align-nonzero.rs b/tests/codegen/dst-vtable-align-nonzero.rs
new file mode 100644
index 000000000..54f6e7f99
--- /dev/null
+++ b/tests/codegen/dst-vtable-align-nonzero.rs
@@ -0,0 +1,61 @@
+// compile-flags: -O -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/dst-vtable-size-range.rs b/tests/codegen/dst-vtable-size-range.rs
new file mode 100644
index 000000000..671c8abde
--- /dev/null
+++ b/tests/codegen/dst-vtable-size-range.rs
@@ -0,0 +1,35 @@
+// compile-flags: -O -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/enum-bounds-check-derived-idx.rs b/tests/codegen/enum-bounds-check-derived-idx.rs
new file mode 100644
index 000000000..aa66c2ed0
--- /dev/null
+++ b/tests/codegen/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: -O
+
+#![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/enum-bounds-check-issue-13926.rs b/tests/codegen/enum-bounds-check-issue-13926.rs
new file mode 100644
index 000000000..b26945bc5
--- /dev/null
+++ b/tests/codegen/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: -O
+
+#![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/enum-bounds-check-issue-82871.rs b/tests/codegen/enum-bounds-check-issue-82871.rs
new file mode 100644
index 000000000..32fdc4a5f
--- /dev/null
+++ b/tests/codegen/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/enum-bounds-check.rs b/tests/codegen/enum-bounds-check.rs
new file mode 100644
index 000000000..17322d591
--- /dev/null
+++ b/tests/codegen/enum-bounds-check.rs
@@ -0,0 +1,26 @@
+// compile-flags: -O
+
+#![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/enum-debug-clike.rs b/tests/codegen/enum-debug-clike.rs
new file mode 100644
index 000000000..1e369a2c4
--- /dev/null
+++ b/tests/codegen/enum-debug-clike.rs
@@ -0,0 +1,23 @@
+// 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
+
+// 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/enum-debug-niche-2.rs b/tests/codegen/enum-debug-niche-2.rs
new file mode 100644
index 000000000..9c72ad9d2
--- /dev/null
+++ b/tests/codegen/enum-debug-niche-2.rs
@@ -0,0 +1,50 @@
+// 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
+
+// compile-flags: -g -C no-prepopulate-passes
+
+// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_variant_part,{{.*}}size: 32,{{.*}}
+// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "Placeholder",{{.*}}extraData: i64 4294967295{{[,)].*}}
+// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "Error",{{.*}}extraData: i64 0{{[,)].*}}
+
+#![feature(never_type)]
+
+#[derive(Copy, Clone)]
+pub struct Entity {
+ private: std::num::NonZeroU32,
+}
+
+#[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/enum-debug-niche.rs b/tests/codegen/enum-debug-niche.rs
new file mode 100644
index 000000000..b718a6854
--- /dev/null
+++ b/tests/codegen/enum-debug-niche.rs
@@ -0,0 +1,29 @@
+// 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
+
+// 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/enum-debug-tagged.rs b/tests/codegen/enum-debug-tagged.rs
new file mode 100644
index 000000000..095c49ac3
--- /dev/null
+++ b/tests/codegen/enum-debug-tagged.rs
@@ -0,0 +1,27 @@
+// 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
+
+// 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/enum-discriminant-value.rs b/tests/codegen/enum-discriminant-value.rs
new file mode 100644
index 000000000..cc14c2120
--- /dev/null
+++ b/tests/codegen/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/enum-match.rs b/tests/codegen/enum-match.rs
new file mode 100644
index 000000000..5f8063a27
--- /dev/null
+++ b/tests/codegen/enum-match.rs
@@ -0,0 +1,109 @@
+// compile-flags: -Copt-level=1
+// only-x86_64
+
+#![crate_type = "lib"]
+
+// Check each of the 3 cases for `codegen_get_discr`.
+
+// Case 0: One tagged variant.
+pub enum Enum0 {
+ A(bool),
+ B,
+}
+
+// CHECK: define noundef i8 @match0{{.*}}
+// CHECK-NEXT: start:
+// CHECK-NEXT: %1 = icmp eq i8 %0, 2
+// CHECK-NEXT: %2 = and i8 %0, 1
+// CHECK-NEXT: %.0 = select i1 %1, i8 13, i8 %2
+#[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: define noundef i8 @match1{{.*}}
+// CHECK-NEXT: start:
+// CHECK-NEXT: [[DISCR:%.*]] = {{.*}}call i8 @llvm.usub.sat.i8(i8 %0, i8 1)
+// CHECK-NEXT: switch i8 [[DISCR]], label {{.*}} [
+#[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.
+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: define noundef i8 @match2{{.*}}
+// CHECK-NEXT: start:
+// CHECK-NEXT: %1 = add i8 %0, 2
+// CHECK-NEXT: %2 = zext i8 %1 to i64
+// CHECK-NEXT: %3 = icmp ult i8 %1, 4
+// CHECK-NEXT: %4 = add nuw nsw i64 %2, 1
+// CHECK-NEXT: %_2 = select i1 %3, i64 %4, i64 0
+// CHECK-NEXT: switch i64 %_2, label {{.*}} [
+#[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,
+ }
+}
diff --git a/tests/codegen/export-no-mangle.rs b/tests/codegen/export-no-mangle.rs
new file mode 100644
index 000000000..a89d48ee1
--- /dev/null
+++ b/tests/codegen/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/external-no-mangle-fns.rs b/tests/codegen/external-no-mangle-fns.rs
new file mode 100644
index 000000000..70349b2ec
--- /dev/null
+++ b/tests/codegen/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/external-no-mangle-statics.rs b/tests/codegen/external-no-mangle-statics.rs
new file mode 100644
index 000000000..c6ecb7aa9
--- /dev/null
+++ b/tests/codegen/external-no-mangle-statics.rs
@@ -0,0 +1,77 @@
+// revisions: lib staticlib
+// ignore-emscripten default visibility is hidden
+// compile-flags: -O
+// [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: @A = local_unnamed_addr constant
+#[no_mangle]
+static A: u8 = 0;
+
+// CHECK: @B = local_unnamed_addr global
+#[no_mangle]
+static mut B: u8 = 0;
+
+// CHECK: @C = local_unnamed_addr constant
+#[no_mangle]
+pub static C: u8 = 0;
+
+// CHECK: @D = local_unnamed_addr global
+#[no_mangle]
+pub static mut D: u8 = 0;
+
+mod private {
+ // CHECK: @E = local_unnamed_addr constant
+ #[no_mangle]
+ static E: u8 = 0;
+
+ // CHECK: @F = local_unnamed_addr global
+ #[no_mangle]
+ static mut F: u8 = 0;
+
+ // CHECK: @G = local_unnamed_addr constant
+ #[no_mangle]
+ pub static G: u8 = 0;
+
+ // CHECK: @H = local_unnamed_addr global
+ #[no_mangle]
+ pub static mut H: u8 = 0;
+}
+
+const HIDDEN: () = {
+ // CHECK: @I = local_unnamed_addr constant
+ #[no_mangle]
+ static I: u8 = 0;
+
+ // CHECK: @J = local_unnamed_addr global
+ #[no_mangle]
+ static mut J: u8 = 0;
+
+ // CHECK: @K = local_unnamed_addr constant
+ #[no_mangle]
+ pub static K: u8 = 0;
+
+ // CHECK: @L = local_unnamed_addr global
+ #[no_mangle]
+ pub static mut L: u8 = 0;
+};
+
+fn x() {
+ // CHECK: @M = local_unnamed_addr constant
+ #[no_mangle]
+ static M: fn() = x;
+
+ // CHECK: @N = local_unnamed_addr global
+ #[no_mangle]
+ static mut N: u8 = 0;
+
+ // CHECK: @O = local_unnamed_addr constant
+ #[no_mangle]
+ pub static O: u8 = 0;
+
+ // CHECK: @P = local_unnamed_addr global
+ #[no_mangle]
+ pub static mut P: u8 = 0;
+}
diff --git a/tests/codegen/fastcall-inreg.rs b/tests/codegen/fastcall-inreg.rs
new file mode 100644
index 000000000..02f5d5459
--- /dev/null
+++ b/tests/codegen/fastcall-inreg.rs
@@ -0,0 +1,41 @@
+// Checks if the "fastcall" calling convention marks function arguments
+// as "inreg" like the C/C++ compilers for the platforms.
+// x86 only.
+
+// compile-flags: --target i686-unknown-linux-gnu -O -C no-prepopulate-passes
+// needs-llvm-components: x86
+
+#![crate_type = "lib"]
+#![no_core]
+#![feature(no_core, lang_items)]
+
+#[lang = "sized"]
+trait Sized {}
+#[lang = "copy"]
+trait Copy {}
+
+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({{i32\*|ptr}} inreg noundef %_1, {{i32\*|ptr}} inreg noundef %_2, {{i32\*|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/fatptr.rs b/tests/codegen/fatptr.rs
new file mode 100644
index 000000000..1c49b5714
--- /dev/null
+++ b/tests/codegen/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/fewer-names.rs b/tests/codegen/fewer-names.rs
new file mode 100644
index 000000000..ac8cba06b
--- /dev/null
+++ b/tests/codegen/fewer-names.rs
@@ -0,0 +1,20 @@
+// no-system-llvm
+// compile-flags: -Coverflow-checks=no -O
+// 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 noundef %0, i32 noundef %1)
+// YES-NEXT: %3 = add i32 %1, %0
+// YES-NEXT: ret i32 %3
+
+// NO-LABEL: define{{.*}}i32 @sum(i32 noundef %x, i32 noundef %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/ffi-const.rs b/tests/codegen/ffi-const.rs
new file mode 100644
index 000000000..937205034
--- /dev/null
+++ b/tests/codegen/ffi-const.rs
@@ -0,0 +1,13 @@
+// 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]+]]
+ // The attribute changed from `readnone` to `memory(none)` with LLVM 16.0.
+ // CHECK-DAG: attributes [[ATTRS]] = { {{.*}}{{readnone|memory\(none\)}}{{.*}} }
+ #[ffi_const] pub fn foo();
+}
diff --git a/tests/codegen/ffi-out-of-bounds-loads.rs b/tests/codegen/ffi-out-of-bounds-loads.rs
new file mode 100644
index 000000000..099726b2f
--- /dev/null
+++ b/tests/codegen/ffi-out-of-bounds-loads.rs
@@ -0,0 +1,25 @@
+// Regression test for #29988
+
+// compile-flags: -C no-prepopulate-passes
+// only-x86_64
+// ignore-windows
+
+#[repr(C)]
+struct S {
+ f1: i32,
+ f2: i32,
+ f3: i32,
+}
+
+extern "C" {
+ fn foo(s: S);
+}
+
+fn main() {
+ let s = S { f1: 1, f2: 2, f3: 3 };
+ unsafe {
+ // CHECK: load { i64, i32 }, {{.*}}, align 4
+ // CHECK: call void @foo({ i64, i32 } {{.*}})
+ foo(s);
+ }
+}
diff --git a/tests/codegen/ffi-pure.rs b/tests/codegen/ffi-pure.rs
new file mode 100644
index 000000000..2ed735813
--- /dev/null
+++ b/tests/codegen/ffi-pure.rs
@@ -0,0 +1,13 @@
+// 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]+]]
+ // The attribute changed from `readonly` to `memory(read)` with LLVM 16.0.
+ // CHECK-DAG: attributes [[ATTRS]] = { {{.*}}{{readonly|memory\(read\)}}{{.*}} }
+ #[ffi_pure] pub fn foo();
+}
diff --git a/tests/codegen/ffi-returns-twice.rs b/tests/codegen/ffi-returns-twice.rs
new file mode 100644
index 000000000..0fbe03f0b
--- /dev/null
+++ b/tests/codegen/ffi-returns-twice.rs
@@ -0,0 +1,11 @@
+// compile-flags: -C no-prepopulate-passes
+#![crate_type = "lib"]
+#![feature(ffi_returns_twice)]
+
+pub fn bar() { unsafe { foo() } }
+
+extern "C" {
+ // CHECK: declare{{( dso_local)?}} void @foo(){{.*}}[[ATTRS:#[0-9]+]]
+ // CHECK: attributes [[ATTRS]] = { {{.*}}returns_twice{{.*}} }
+ #[ffi_returns_twice] pub fn foo();
+}
diff --git a/tests/codegen/float_math.rs b/tests/codegen/float_math.rs
new file mode 100644
index 000000000..592e09452
--- /dev/null
+++ b/tests/codegen/float_math.rs
@@ -0,0 +1,50 @@
+// compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+use std::intrinsics::{fadd_fast, fsub_fast, fmul_fast, fdiv_fast, frem_fast};
+
+// CHECK-LABEL: @add
+#[no_mangle]
+pub fn add(x: f32, y: f32) -> f32 {
+// CHECK: fadd float
+// CHECK-NOT: fast
+ x + y
+}
+
+// CHECK-LABEL: @addition
+#[no_mangle]
+pub fn addition(x: f32, y: f32) -> f32 {
+// CHECK: fadd fast float
+ unsafe {
+ fadd_fast(x, y)
+ }
+}
+
+// CHECK-LABEL: @subtraction
+#[no_mangle]
+pub fn subtraction(x: f32, y: f32) -> f32 {
+// CHECK: fsub fast float
+ unsafe {
+ fsub_fast(x, y)
+ }
+}
+
+// CHECK-LABEL: @multiplication
+#[no_mangle]
+pub fn multiplication(x: f32, y: f32) -> f32 {
+// CHECK: fmul fast float
+ unsafe {
+ fmul_fast(x, y)
+ }
+}
+
+// CHECK-LABEL: @division
+#[no_mangle]
+pub fn division(x: f32, y: f32) -> f32 {
+// CHECK: fdiv fast float
+ unsafe {
+ fdiv_fast(x, y)
+ }
+}
diff --git a/tests/codegen/fn-impl-trait-self.rs b/tests/codegen/fn-impl-trait-self.rs
new file mode 100644
index 000000000..0abc8a409
--- /dev/null
+++ b/tests/codegen/fn-impl-trait-self.rs
@@ -0,0 +1,16 @@
+// compile-flags: -g
+//
+// 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/foo.s b/tests/codegen/foo.s
new file mode 100644
index 000000000..304d82aa0
--- /dev/null
+++ b/tests/codegen/foo.s
@@ -0,0 +1,3 @@
+.global foo
+foo:
+ jmp baz
diff --git a/tests/codegen/force-frame-pointers.rs b/tests/codegen/force-frame-pointers.rs
new file mode 100644
index 000000000..637c42346
--- /dev/null
+++ b/tests/codegen/force-frame-pointers.rs
@@ -0,0 +1,6 @@
+// compile-flags: -C no-prepopulate-passes -C force-frame-pointers=y
+
+#![crate_type="lib"]
+
+// CHECK: attributes #{{.*}} "frame-pointer"="all"
+pub fn foo() {}
diff --git a/tests/codegen/force-no-unwind-tables.rs b/tests/codegen/force-no-unwind-tables.rs
new file mode 100644
index 000000000..3ee23f05e
--- /dev/null
+++ b/tests/codegen/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
+
+#![crate_type="lib"]
+
+// CHECK-LABEL: define{{.*}}void @foo
+// CHECK-NOT: attributes #{{.*}} uwtable
+#[no_mangle]
+fn foo() {
+ panic!();
+}
diff --git a/tests/codegen/force-unwind-tables.rs b/tests/codegen/force-unwind-tables.rs
new file mode 100644
index 000000000..4c0a5602c
--- /dev/null
+++ b/tests/codegen/force-unwind-tables.rs
@@ -0,0 +1,6 @@
+// compile-flags: -C no-prepopulate-passes -C force-unwind-tables=y
+
+#![crate_type="lib"]
+
+// CHECK: attributes #{{.*}} uwtable
+pub fn foo() {}
diff --git a/tests/codegen/frame-pointer.rs b/tests/codegen/frame-pointer.rs
new file mode 100644
index 000000000..d8933262e
--- /dev/null
+++ b/tests/codegen/frame-pointer.rs
@@ -0,0 +1,35 @@
+// 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]
+#[lang="sized"]
+trait Sized { }
+#[lang="copy"]
+trait Copy { }
+impl Copy for u32 {}
+
+
+// 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"{{.*}}
+// aarch64-linux-NOT: {{.*}}"frame-pointer"{{.*}}
+// x64-apple-SAME: {{.*}}"frame-pointer"="all"
+// force-SAME: {{.*}}"frame-pointer"="all"
+// aarch64-apple-SAME: {{.*}}"frame-pointer"="non-leaf"
+// CHECK-SAME: }
diff --git a/tests/codegen/function-arguments-noopt.rs b/tests/codegen/function-arguments-noopt.rs
new file mode 100644
index 000000000..ff76405a4
--- /dev/null
+++ b/tests/codegen/function-arguments-noopt.rs
@@ -0,0 +1,63 @@
+// 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 {{i32\*|ptr}} @borrow({{i32\*|ptr}} align 4 %x)
+#[no_mangle]
+pub fn borrow(x: &i32) -> &i32 {
+ x
+}
+
+// CHECK-LABEL: @borrow_call
+#[no_mangle]
+pub fn borrow_call(x: &i32, f: fn(&i32) -> &i32) -> &i32 {
+ // CHECK: call align 4 {{i32\*|ptr}} %f({{i32\*|ptr}} align 4 %x)
+ f(x)
+}
+
+// CHECK: void @struct_({{%S\*|ptr}} sret(%S){{( %0)?}}, {{%S\*|ptr}} %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({{%S\*|ptr}} sret(%S){{( %0)?}}, {{%S\*|ptr}} %{{.+}})
+ f(x)
+}
+
+// CHECK: { i8, 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 { i8, i8 } %f(i1 zeroext %x.0, i8 %x.1)
+ f(x)
+}
diff --git a/tests/codegen/function-arguments.rs b/tests/codegen/function-arguments.rs
new file mode 100644
index 000000000..1f979d7b9
--- /dev/null
+++ b/tests/codegen/function-arguments.rs
@@ -0,0 +1,261 @@
+// compile-flags: -O -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+use std::mem::MaybeUninit;
+use std::num::NonZeroU64;
+use std::marker::PhantomPinned;
+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 i32 @char(i32 noundef %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 i64 @nonzero_int(i64 noundef %x)
+#[no_mangle]
+pub fn nonzero_int(x: NonZeroU64) -> NonZeroU64 {
+ x
+}
+
+// CHECK: noundef i64 @option_nonzero_int(i64 noundef %x)
+#[no_mangle]
+pub fn option_nonzero_int(x: Option<NonZeroU64>) -> Option<NonZeroU64> {
+ x
+}
+
+// CHECK: @readonly_borrow({{i32\*|ptr}} noalias noundef readonly align 4 dereferenceable(4) %_1)
+// FIXME #25759 This should also have `nocapture`
+#[no_mangle]
+pub fn readonly_borrow(_: &i32) {
+}
+
+// CHECK: @static_borrow({{i32\*|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({{i32\*|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({{i16\*|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({{i16\*|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({{i32\*|ptr}} noalias noundef align 4 dereferenceable(4) %_1)
+// FIXME #25759 This should also have `nocapture`
+#[no_mangle]
+pub fn mutable_borrow(_: &mut i32) {
+}
+
+#[no_mangle]
+// CHECK: @mutable_notunpin_borrow({{i32\*|ptr}} noundef align 4 dereferenceable(4) %_1)
+// This one is *not* `noalias` because it might be self-referential.
+pub fn mutable_notunpin_borrow(_: &mut NotUnpin) {
+}
+
+// CHECK: @notunpin_borrow({{i32\*|ptr}} noalias noundef readonly align 4 dereferenceable(4) %_1)
+// But `&NotUnpin` behaves perfectly normal.
+#[no_mangle]
+pub fn notunpin_borrow(_: &NotUnpin) {
+}
+
+// CHECK: @indirect_struct({{%S\*|ptr}} noalias nocapture noundef readonly dereferenceable(32) %_1)
+#[no_mangle]
+pub fn indirect_struct(_: S) {
+}
+
+// CHECK: @borrowed_struct({{%S\*|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({{i32\*|ptr}} noalias noundef readonly align 4 dereferenceable_or_null(4) %x)
+#[no_mangle]
+pub fn option_borrow(x: Option<&i32>) {
+}
+
+// CHECK: @option_borrow_mut({{i32\*|ptr}} noalias noundef align 4 dereferenceable_or_null(4) %x)
+#[no_mangle]
+pub fn option_borrow_mut(x: Option<&mut i32>) {
+}
+
+// CHECK: @raw_struct({{%S\*|ptr}} noundef %_1)
+#[no_mangle]
+pub fn raw_struct(_: *const S) {
+}
+
+// CHECK: @raw_option_nonnull_struct({{i32\*|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 {{i32\*|ptr}} @_box({{i32\*|ptr}} noalias noundef nonnull align 4 %x)
+#[no_mangle]
+pub fn _box(x: Box<i32>) -> Box<i32> {
+ x
+}
+
+// CHECK: @struct_return({{%S\*|ptr}} noalias nocapture noundef sret(%S) 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({{\[0 x i8\]\*|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({{\[0 x i8\]\*|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({{\[0 x i16\]\*|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({{\[0 x i8\]\*|ptr}} noundef %_1.0, [[USIZE]] noundef %_1.1)
+#[no_mangle]
+pub fn raw_slice(_: *const [u8]) {
+}
+
+// CHECK: @str({{\[0 x i8\]\*|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({{i8\*|ptr}} noundef align 1 %x.0, {{i8\*|ptr}} %x.1)
+#[no_mangle]
+pub fn option_trait_borrow(x: Option<&dyn Drop>) {
+}
+
+// CHECK: @option_trait_borrow_mut({{i8\*|ptr}} noundef align 1 %x.0, {{i8\*|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>) {
+}
+
+// CHECK: { {{i8\*|ptr}}, {{i8\*|ptr}} } @trait_option({{i8\*|ptr}} noalias noundef align 1 %x.0, {{i8\*|ptr}} %x.1)
+#[no_mangle]
+pub fn trait_option(x: Option<Box<dyn Drop>>) -> Option<Box<dyn Drop>> {
+ x
+}
+
+// CHECK: { {{\[0 x i16\]\*|ptr}}, [[USIZE]] } @return_slice({{\[0 x i16\]\*|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 %x.0, i16 %x.1)
+#[no_mangle]
+pub fn enum_id_1(x: Option<Result<u16, u16>>) -> Option<Result<u16, u16>> {
+ x
+}
+
+// CHECK: { i8, 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/gdb_debug_script_load.rs b/tests/codegen/gdb_debug_script_load.rs
new file mode 100644
index 000000000..002be8d1b
--- /dev/null
+++ b/tests/codegen/gdb_debug_script_load.rs
@@ -0,0 +1,17 @@
+//
+// ignore-windows
+// ignore-macos
+// ignore-wasm
+// ignore-emscripten
+
+// compile-flags: -g -C no-prepopulate-passes
+
+#![feature(start)]
+
+// CHECK-LABEL: @main
+// CHECK: load volatile i8, {{.+}} @__rustc_debug_gdb_scripts_section__
+
+#[start]
+fn start(_: isize, _: *const *const u8) -> isize {
+ return 0;
+}
diff --git a/tests/codegen/generator-debug-msvc.rs b/tests/codegen/generator-debug-msvc.rs
new file mode 100644
index 000000000..9d70ccdef
--- /dev/null
+++ b/tests/codegen/generator-debug-msvc.rs
@@ -0,0 +1,59 @@
+// Verify debuginfo for generators:
+// - 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(generators, generator_trait)]
+use std::ops::Generator;
+
+fn generator_test() -> impl Generator<Yield = i32, Return = ()> {
+ || {
+ 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$<generator_debug_msvc::generator_test::generator_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: 14,
+// CHECK-NOT: flags: DIFlagArtificial
+// CHECK-SAME: )
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant1", scope: [[GEN]],
+// CHECK-SAME: file: [[FILE]], line: 18,
+// CHECK-NOT: flags: DIFlagArtificial
+// CHECK-SAME: )
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant2", scope: [[GEN]],
+// CHECK-SAME: file: [[FILE]], line: 18,
+// CHECK-NOT: flags: DIFlagArtificial
+// CHECK-SAME: )
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant3", scope: [[GEN]],
+// CHECK-SAME: file: [[FILE]], line: 15,
+// CHECK-NOT: flags: DIFlagArtificial
+// CHECK-SAME: )
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant4", scope: [[GEN]],
+// CHECK-SAME: file: [[FILE]], line: 17,
+// 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 = generator_test();
+}
diff --git a/tests/codegen/generator-debug.rs b/tests/codegen/generator-debug.rs
new file mode 100644
index 000000000..3ec860f2c
--- /dev/null
+++ b/tests/codegen/generator-debug.rs
@@ -0,0 +1,62 @@
+// Verify debuginfo for generators:
+// - 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(generators, generator_trait)]
+use std::ops::Generator;
+
+fn generator_test() -> impl Generator<Yield = i32, Return = ()> {
+ || {
+ yield 0;
+ let s = String::from("foo");
+ yield 1;
+ }
+}
+
+// FIXME: No way to reliably check the filename.
+
+// CHECK-DAG: [[GEN_FN:!.*]] = !DINamespace(name: "generator_test"
+// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "{generator_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: 14,
+// 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: 18,
+// CHECK-NOT: flags: DIFlagArtificial
+// CHECK-SAME: )
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "2", scope: [[VARIANT]],
+// CHECK-SAME: file: [[FILE]], line: 18,
+// CHECK-NOT: flags: DIFlagArtificial
+// CHECK-SAME: )
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "3", scope: [[VARIANT]],
+// CHECK-SAME: file: [[FILE]], line: 15,
+// CHECK-NOT: flags: DIFlagArtificial
+// CHECK-SAME: )
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "4", scope: [[VARIANT]],
+// CHECK-SAME: file: [[FILE]], line: 17,
+// 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 = generator_test();
+}
diff --git a/tests/codegen/generic-debug.rs b/tests/codegen/generic-debug.rs
new file mode 100644
index 000000000..eea16805c
--- /dev/null
+++ b/tests/codegen/generic-debug.rs
@@ -0,0 +1,17 @@
+// ignore-windows
+
+// 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/global_asm.rs b/tests/codegen/global_asm.rs
new file mode 100644
index 000000000..fab84868f
--- /dev/null
+++ b/tests/codegen/global_asm.rs
@@ -0,0 +1,64 @@
+// ignore-aarch64
+// ignore-aarch64_be
+// ignore-arm
+// ignore-armeb
+// ignore-avr
+// ignore-bpfel
+// ignore-bpfeb
+// ignore-hexagon
+// ignore-mips
+// ignore-mips64
+// ignore-msp430
+// ignore-powerpc64
+// ignore-powerpc64le
+// ignore-powerpc
+// ignore-r600
+// ignore-amdgcn
+// ignore-sparc
+// ignore-sparcv9
+// ignore-sparcel
+// ignore-s390x
+// ignore-tce
+// ignore-thumb
+// ignore-thumbeb
+// ignore-xcore
+// ignore-nvptx
+// ignore-nvptx64
+// ignore-le32
+// ignore-le64
+// ignore-amdil
+// ignore-amdil64
+// ignore-hsail
+// ignore-hsail64
+// ignore-spir
+// ignore-spir64
+// ignore-kalimba
+// ignore-shave
+// ignore-wasm32
+// ignore-wasm64
+// ignore-emscripten
+// 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/global_asm_include.rs b/tests/codegen/global_asm_include.rs
new file mode 100644
index 000000000..02ee91645
--- /dev/null
+++ b/tests/codegen/global_asm_include.rs
@@ -0,0 +1,57 @@
+// ignore-aarch64
+// ignore-aarch64_be
+// ignore-arm
+// ignore-armeb
+// ignore-avr
+// ignore-bpfel
+// ignore-bpfeb
+// ignore-hexagon
+// ignore-mips
+// ignore-mips64
+// ignore-msp430
+// ignore-powerpc64
+// ignore-powerpc64le
+// ignore-powerpc
+// ignore-r600
+// ignore-amdgcn
+// ignore-sparc
+// ignore-sparcv9
+// ignore-sparcel
+// ignore-s390x
+// ignore-tce
+// ignore-thumb
+// ignore-thumbeb
+// ignore-xcore
+// ignore-nvptx
+// ignore-nvptx64
+// ignore-le32
+// ignore-le64
+// ignore-amdil
+// ignore-amdil64
+// ignore-hsail
+// ignore-hsail64
+// ignore-spir
+// ignore-spir64
+// ignore-kalimba
+// ignore-shave
+// ignore-wasm32
+// ignore-wasm64
+// ignore-emscripten
+// 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/global_asm_x2.rs b/tests/codegen/global_asm_x2.rs
new file mode 100644
index 000000000..bdcf0ea84
--- /dev/null
+++ b/tests/codegen/global_asm_x2.rs
@@ -0,0 +1,83 @@
+// ignore-aarch64
+// ignore-aarch64_be
+// ignore-arm
+// ignore-armeb
+// ignore-avr
+// ignore-bpfel
+// ignore-bpfeb
+// ignore-hexagon
+// ignore-mips
+// ignore-mips64
+// ignore-msp430
+// ignore-powerpc64
+// ignore-powerpc64le
+// ignore-powerpc
+// ignore-r600
+// ignore-amdgcn
+// ignore-sparc
+// ignore-sparcv9
+// ignore-sparcel
+// ignore-s390x
+// ignore-tce
+// ignore-thumb
+// ignore-thumbeb
+// ignore-xcore
+// ignore-nvptx
+// ignore-nvptx64
+// ignore-le32
+// ignore-le64
+// ignore-amdil
+// ignore-amdil64
+// ignore-hsail
+// ignore-hsail64
+// ignore-spir
+// ignore-spir64
+// ignore-kalimba
+// ignore-shave
+// ignore-wasm32
+// ignore-wasm64
+// ignore-emscripten
+// 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/i686-macosx-deployment-target.rs b/tests/codegen/i686-macosx-deployment-target.rs
new file mode 100644
index 000000000..17258a264
--- /dev/null
+++ b/tests/codegen/i686-macosx-deployment-target.rs
@@ -0,0 +1,27 @@
+//
+// Checks that we correctly modify the target when MACOSX_DEPLOYMENT_TARGET is set.
+// See issue #60235.
+
+// compile-flags: -O --target=i686-apple-darwin --crate-type=rlib
+// needs-llvm-components: x86
+// rustc-env:MACOSX_DEPLOYMENT_TARGET=10.9
+#![feature(no_core, lang_items)]
+#![no_core]
+
+#[lang="sized"]
+trait Sized { }
+#[lang="freeze"]
+trait Freeze { }
+#[lang="copy"]
+trait Copy { }
+
+#[repr(C)]
+pub struct Bool {
+ b: bool,
+}
+
+// CHECK: target triple = "i686-apple-macosx10.9.0"
+#[no_mangle]
+pub extern "C" fn structbool() -> Bool {
+ Bool { b: true }
+}
diff --git a/tests/codegen/i686-no-macosx-deployment-target.rs b/tests/codegen/i686-no-macosx-deployment-target.rs
new file mode 100644
index 000000000..043040a95
--- /dev/null
+++ b/tests/codegen/i686-no-macosx-deployment-target.rs
@@ -0,0 +1,27 @@
+//
+// Checks that we leave the target alone MACOSX_DEPLOYMENT_TARGET is unset.
+// See issue #60235.
+
+// compile-flags: -O --target=i686-apple-darwin --crate-type=rlib
+// needs-llvm-components: x86
+// unset-rustc-env:MACOSX_DEPLOYMENT_TARGET
+#![feature(no_core, lang_items)]
+#![no_core]
+
+#[lang="sized"]
+trait Sized { }
+#[lang="freeze"]
+trait Freeze { }
+#[lang="copy"]
+trait Copy { }
+
+#[repr(C)]
+pub struct Bool {
+ b: bool,
+}
+
+// CHECK: target triple = "i686-apple-macosx10.7.0"
+#[no_mangle]
+pub extern "C" fn structbool() -> Bool {
+ Bool { b: true }
+}
diff --git a/tests/codegen/inline-always-works-always.rs b/tests/codegen/inline-always-works-always.rs
new file mode 100644
index 000000000..912af782a
--- /dev/null
+++ b/tests/codegen/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/inline-debuginfo.rs b/tests/codegen/inline-debuginfo.rs
new file mode 100644
index 000000000..5b230361f
--- /dev/null
+++ b/tests/codegen/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: call void @llvm.dbg.value(metadata i32 %y, metadata !{{.*}}, metadata !DIExpression(DW_OP_constu, 3, DW_OP_minus, DW_OP_stack_value)), !dbg [[A:!.*]]
+// CHECK: [[A]] = !DILocation(line: {{.*}}, scope: {{.*}}, inlinedAt: {{.*}})
+#[no_mangle]
+pub extern "C" fn caller(y: u32) -> u32 {
+ callee(y - 3)
+}
diff --git a/tests/codegen/inline-hint.rs b/tests/codegen/inline-hint.rs
new file mode 100644
index 000000000..d3ea1915a
--- /dev/null
+++ b/tests/codegen/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
+#![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/instrument-coverage.rs b/tests/codegen/instrument-coverage.rs
new file mode 100644
index 000000000..78f8875a2
--- /dev/null
+++ b/tests/codegen/instrument-coverage.rs
@@ -0,0 +1,17 @@
+// Test that `-Cinstrument-coverage` creates expected __llvm_profile_filename symbol in LLVM IR.
+
+// needs-profiler-support
+// compile-flags: -Cinstrument-coverage
+
+// CHECK: @__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/instrument-mcount.rs b/tests/codegen/instrument-mcount.rs
new file mode 100644
index 000000000..b26076e7a
--- /dev/null
+++ b/tests/codegen/instrument-mcount.rs
@@ -0,0 +1,7 @@
+//
+// compile-flags: -Z instrument-mcount
+
+#![crate_type = "lib"]
+
+// CHECK: attributes #{{.*}} "frame-pointer"="all" "instrument-function-entry-inlined"="{{.*}}mcount{{.*}}"
+pub fn foo() {}
diff --git a/tests/codegen/integer-cmp.rs b/tests/codegen/integer-cmp.rs
new file mode 100644
index 000000000..8ada3cf09
--- /dev/null
+++ b/tests/codegen/integer-cmp.rs
@@ -0,0 +1,28 @@
+// This is test for more optimal Ord implementation for integers.
+// See <https://github.com/rust-lang/rust/issues/63758> for more info.
+
+// compile-flags: -C opt-level=3
+
+#![crate_type = "lib"]
+
+use std::cmp::Ordering;
+
+// CHECK-LABEL: @cmp_signed
+#[no_mangle]
+pub fn cmp_signed(a: i64, b: i64) -> Ordering {
+// CHECK: icmp slt
+// CHECK: icmp ne
+// CHECK: zext i1
+// CHECK: select i1
+ a.cmp(&b)
+}
+
+// CHECK-LABEL: @cmp_unsigned
+#[no_mangle]
+pub fn cmp_unsigned(a: u32, b: u32) -> Ordering {
+// CHECK: icmp ult
+// CHECK: icmp ne
+// CHECK: zext i1
+// CHECK: select i1
+ a.cmp(&b)
+}
diff --git a/tests/codegen/integer-overflow.rs b/tests/codegen/integer-overflow.rs
new file mode 100644
index 000000000..183de56db
--- /dev/null
+++ b/tests/codegen/integer-overflow.rs
@@ -0,0 +1,26 @@
+// no-system-llvm
+// compile-flags: -O -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/internalize-closures.rs b/tests/codegen/internalize-closures.rs
new file mode 100644
index 000000000..ab3dc3fba
--- /dev/null
+++ b/tests/codegen/internalize-closures.rs
@@ -0,0 +1,14 @@
+// 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/intrinsic-no-unnamed-attr.rs b/tests/codegen/intrinsic-no-unnamed-attr.rs
new file mode 100644
index 000000000..c8a8e0b3e
--- /dev/null
+++ b/tests/codegen/intrinsic-no-unnamed-attr.rs
@@ -0,0 +1,12 @@
+// compile-flags: -C no-prepopulate-passes
+
+#![feature(intrinsics)]
+
+extern "rust-intrinsic" {
+ fn sqrtf32(x: f32) -> f32;
+}
+// CHECK: @llvm.sqrt.f32(float) #{{[0-9]*}}
+
+fn main() {
+ unsafe { sqrtf32(0.0f32); }
+}
diff --git a/tests/codegen/intrinsics/const_eval_select.rs b/tests/codegen/intrinsics/const_eval_select.rs
new file mode 100644
index 000000000..f3877dc6b
--- /dev/null
+++ b/tests/codegen/intrinsics/const_eval_select.rs
@@ -0,0 +1,18 @@
+// 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/intrinsics/exact_div.rs b/tests/codegen/intrinsics/exact_div.rs
new file mode 100644
index 000000000..68eaa3999
--- /dev/null
+++ b/tests/codegen/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/intrinsics/likely.rs b/tests/codegen/intrinsics/likely.rs
new file mode 100644
index 000000000..c5a0185bd
--- /dev/null
+++ b/tests/codegen/intrinsics/likely.rs
@@ -0,0 +1,30 @@
+// compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+use std::intrinsics::{likely,unlikely};
+
+#[no_mangle]
+pub fn check_likely(x: i32, y: i32) -> Option<i32> {
+ unsafe {
+ // CHECK: call i1 @llvm.expect.i1(i1 %{{.*}}, i1 true)
+ if likely(x == y) {
+ None
+ } else {
+ Some(x + y)
+ }
+ }
+}
+
+#[no_mangle]
+pub fn check_unlikely(x: i32, y: i32) -> Option<i32> {
+ unsafe {
+ // CHECK: call i1 @llvm.expect.i1(i1 %{{.*}}, i1 false)
+ if unlikely(x == y) {
+ None
+ } else {
+ Some(x + y)
+ }
+ }
+}
diff --git a/tests/codegen/intrinsics/mask.rs b/tests/codegen/intrinsics/mask.rs
new file mode 100644
index 000000000..8f93da2e5
--- /dev/null
+++ b/tests/codegen/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|i8\*}} {{%ptr|%1}}, [[WORD]] %mask)
+ core::intrinsics::ptr_mask(ptr, mask)
+}
diff --git a/tests/codegen/intrinsics/nearby.rs b/tests/codegen/intrinsics/nearby.rs
new file mode 100644
index 000000000..520fe2f18
--- /dev/null
+++ b/tests/codegen/intrinsics/nearby.rs
@@ -0,0 +1,18 @@
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+use std::intrinsics;
+
+// CHECK-LABEL: @nearbyintf32
+#[no_mangle]
+pub unsafe fn nearbyintf32(a: f32) -> f32 {
+ // CHECK: llvm.nearbyint.f32
+ intrinsics::nearbyintf32(a)
+}
+
+// CHECK-LABEL: @nearbyintf64
+#[no_mangle]
+pub unsafe fn nearbyintf64(a: f64) -> f64 {
+ // CHECK: llvm.nearbyint.f64
+ intrinsics::nearbyintf64(a)
+}
diff --git a/tests/codegen/intrinsics/nontemporal.rs b/tests/codegen/intrinsics/nontemporal.rs
new file mode 100644
index 000000000..d8ee29452
--- /dev/null
+++ b/tests/codegen/intrinsics/nontemporal.rs
@@ -0,0 +1,13 @@
+// compile-flags: -O
+
+#![feature(core_intrinsics)]
+#![crate_type = "lib"]
+
+#[no_mangle]
+pub fn a(a: &mut u32, b: u32) {
+ // CHECK-LABEL: define{{.*}}void @a
+ // CHECK: store i32 %b, {{i32\*|ptr}} %a, align 4, !nontemporal
+ unsafe {
+ std::intrinsics::nontemporal_store(a, b);
+ }
+}
diff --git a/tests/codegen/intrinsics/offset_from.rs b/tests/codegen/intrinsics/offset_from.rs
new file mode 100644
index 000000000..d0de4c835
--- /dev/null
+++ b/tests/codegen/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/intrinsics/prefetch.rs b/tests/codegen/intrinsics/prefetch.rs
new file mode 100644
index 000000000..59d7fa638
--- /dev/null
+++ b/tests/codegen/intrinsics/prefetch.rs
@@ -0,0 +1,63 @@
+// compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+use std::intrinsics::{prefetch_read_data, prefetch_write_data,
+ prefetch_read_instruction, 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/intrinsics/unchecked_math.rs b/tests/codegen/intrinsics/unchecked_math.rs
new file mode 100644
index 000000000..419c120ed
--- /dev/null
+++ b/tests/codegen/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/intrinsics/volatile.rs b/tests/codegen/intrinsics/volatile.rs
new file mode 100644
index 000000000..7980c00e7
--- /dev/null
+++ b/tests/codegen/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/intrinsics/volatile_order.rs b/tests/codegen/intrinsics/volatile_order.rs
new file mode 100644
index 000000000..99469831a
--- /dev/null
+++ b/tests/codegen/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/issue-103285-ptr-addr-overflow-check.rs b/tests/codegen/issue-103285-ptr-addr-overflow-check.rs
new file mode 100644
index 000000000..a3499babe
--- /dev/null
+++ b/tests/codegen/issue-103285-ptr-addr-overflow-check.rs
@@ -0,0 +1,16 @@
+// compile-flags: -O -C debug-assertions=yes
+
+#![crate_type = "lib"]
+#![feature(strict_provenance)]
+
+#[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/issue-103840.rs b/tests/codegen/issue-103840.rs
new file mode 100644
index 000000000..f19d7031b
--- /dev/null
+++ b/tests/codegen/issue-103840.rs
@@ -0,0 +1,9 @@
+// compile-flags: -O
+#![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/issue-105386-ub-in-debuginfo.rs b/tests/codegen/issue-105386-ub-in-debuginfo.rs
new file mode 100644
index 000000000..d54ac9e33
--- /dev/null
+++ b/tests/codegen/issue-105386-ub-in-debuginfo.rs
@@ -0,0 +1,22 @@
+// compile-flags: --crate-type=lib -O -Cdebuginfo=2 -Cno-prepopulate-passes
+// min-llvm-version: 15.0 # this test uses opaque pointer notation
+#![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 %"[closure@{{.*.rs}}:9:23: 9:25]"
+// CHECK-NOT: [[ptr_tmp:%.*]] = getelementptr inbounds %"[closure@{{.*.rs}}:9:23: 9:25]", ptr [[spill]]
+// CHECK-NOT: [[load:%.*]] = load ptr, ptr
+// CHECK: call void @llvm.lifetime.start{{.*}}({{.*}}, ptr [[spill]])
+// CHECK: call void @llvm.memcpy{{.*}}(ptr {{align .*}} [[spill]], ptr {{align .*}} %x
diff --git a/tests/codegen/issue-13018.rs b/tests/codegen/issue-13018.rs
new file mode 100644
index 000000000..b70ea1f48
--- /dev/null
+++ b/tests/codegen/issue-13018.rs
@@ -0,0 +1,11 @@
+// compile-flags: -O
+
+// A drop([...].clone()) sequence on an Rc should be a no-op
+// In particular, no call to __rust_dealloc should be emitted
+#![crate_type = "lib"]
+use std::rc::Rc;
+
+pub fn foo(t: &Rc<Vec<usize>>) {
+// CHECK-NOT: __rust_dealloc
+ drop(t.clone());
+}
diff --git a/tests/codegen/issue-15953.rs b/tests/codegen/issue-15953.rs
new file mode 100644
index 000000000..28d284289
--- /dev/null
+++ b/tests/codegen/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 };
+ 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/issue-27130.rs b/tests/codegen/issue-27130.rs
new file mode 100644
index 000000000..e5ee94e1f
--- /dev/null
+++ b/tests/codegen/issue-27130.rs
@@ -0,0 +1,21 @@
+// compile-flags: -O
+
+#![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/issue-32031.rs b/tests/codegen/issue-32031.rs
new file mode 100644
index 000000000..abef92c19
--- /dev/null
+++ b/tests/codegen/issue-32031.rs
@@ -0,0 +1,23 @@
+// compile-flags: -C no-prepopulate-passes -Copt-level=0
+
+#![crate_type = "lib"]
+
+#[no_mangle]
+pub struct F32(f32);
+
+// CHECK: define{{.*}}float @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);
+
+// CHECK: define{{.*}}double @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/issue-32364.rs b/tests/codegen/issue-32364.rs
new file mode 100644
index 000000000..85493a4bb
--- /dev/null
+++ b/tests/codegen/issue-32364.rs
@@ -0,0 +1,18 @@
+// 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/issue-34634.rs b/tests/codegen/issue-34634.rs
new file mode 100644
index 000000000..f53fa240c
--- /dev/null
+++ b/tests/codegen/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: -O
+#![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/issue-34947-pow-i32.rs b/tests/codegen/issue-34947-pow-i32.rs
new file mode 100644
index 000000000..653da8e8b
--- /dev/null
+++ b/tests/codegen/issue-34947-pow-i32.rs
@@ -0,0 +1,13 @@
+// compile-flags: -O
+
+#![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/issue-37945.rs b/tests/codegen/issue-37945.rs
new file mode 100644
index 000000000..fe54375bb
--- /dev/null
+++ b/tests/codegen/issue-37945.rs
@@ -0,0 +1,38 @@
+// compile-flags: -O -Zmerge-functions=disabled
+// ignore-x86
+// ignore-arm
+// ignore-emscripten
+// ignore-gnux32
+// ignore 32-bit platforms (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 {{i32\*|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 {{i32\*|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 {{i32\*|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 {{i32\*|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/issue-44056-macos-tls-align.rs b/tests/codegen/issue-44056-macos-tls-align.rs
new file mode 100644
index 000000000..1a3923f1b
--- /dev/null
+++ b/tests/codegen/issue-44056-macos-tls-align.rs
@@ -0,0 +1,28 @@
+//
+// only-macos
+// no-system-llvm
+// compile-flags: -O
+
+#![crate_type = "rlib"]
+#![feature(thread_local)]
+
+// local_unnamed_addr does not appear when std is built with debug assertions.
+// CHECK: @STATIC_VAR_1 = thread_local {{(local_unnamed_addr )?}}global <{ [32 x i8] }> zeroinitializer, section "__DATA,__thread_bss", align 4
+#[no_mangle]
+#[thread_local]
+static mut STATIC_VAR_1: [u32; 8] = [0; 8];
+
+// CHECK: @STATIC_VAR_2 = thread_local {{(local_unnamed_addr )?}}global <{ [32 x i8] }> <{{[^>]*}}>, section "__DATA,__thread_data", align 4
+#[no_mangle]
+#[thread_local]
+static mut STATIC_VAR_2: [u32; 8] = [4; 8];
+
+#[no_mangle]
+pub unsafe fn f(x: &mut [u32; 8]) {
+ std::mem::swap(x, &mut STATIC_VAR_1)
+}
+
+#[no_mangle]
+pub unsafe fn g(x: &mut [u32; 8]) {
+ std::mem::swap(x, &mut STATIC_VAR_2)
+}
diff --git a/tests/codegen/issue-45222.rs b/tests/codegen/issue-45222.rs
new file mode 100644
index 000000000..e9b05e648
--- /dev/null
+++ b/tests/codegen/issue-45222.rs
@@ -0,0 +1,63 @@
+// compile-flags: -O
+// ignore-debug: the debug assertions get in the way
+
+#![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/issue-45466.rs b/tests/codegen/issue-45466.rs
new file mode 100644
index 000000000..c79542767
--- /dev/null
+++ b/tests/codegen/issue-45466.rs
@@ -0,0 +1,15 @@
+// compile-flags: -O
+// ignore-debug: the debug assertions get in the way
+
+#![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/issue-45964-bounds-check-slice-pos.rs b/tests/codegen/issue-45964-bounds-check-slice-pos.rs
new file mode 100644
index 000000000..1daa213fc
--- /dev/null
+++ b/tests/codegen/issue-45964-bounds-check-slice-pos.rs
@@ -0,0 +1,39 @@
+// This test case checks that slice::{r}position functions do not
+// prevent optimizing away bounds checks
+
+// compile-flags: -O
+// ignore-debug: the debug assertions get in the way
+
+#![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/issue-47278.rs b/tests/codegen/issue-47278.rs
new file mode 100644
index 000000000..9076274f4
--- /dev/null
+++ b/tests/codegen/issue-47278.rs
@@ -0,0 +1,9 @@
+// -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/issue-47442.rs b/tests/codegen/issue-47442.rs
new file mode 100644
index 000000000..6944336d3
--- /dev/null
+++ b/tests/codegen/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/issue-56267-2.rs b/tests/codegen/issue-56267-2.rs
new file mode 100644
index 000000000..4dc9ebfeb
--- /dev/null
+++ b/tests/codegen/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, {{i32\*|ptr}} %{{.+}}, align 4
+#[no_mangle]
+pub fn test(x: Foo<(i32, i32)>) -> (i32, i32) {
+ x.bar
+}
diff --git a/tests/codegen/issue-56267.rs b/tests/codegen/issue-56267.rs
new file mode 100644
index 000000000..7bdd25779
--- /dev/null
+++ b/tests/codegen/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:%.+]], {{i32\*|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/issue-56927.rs b/tests/codegen/issue-56927.rs
new file mode 100644
index 000000000..044d72181
--- /dev/null
+++ b/tests/codegen/issue-56927.rs
@@ -0,0 +1,43 @@
+// compile-flags: -C no-prepopulate-passes
+
+#![crate_type="rlib"]
+
+#[repr(align(16))]
+pub struct S {
+ arr: [u32; 4],
+}
+
+// CHECK-LABEL: @test1
+// CHECK: store i32 0, {{i32\*|ptr}} %{{.+}}, align 16
+// CHECK: store i32 1, {{i32\*|ptr}} %{{.+}}, align 4
+// CHECK: store i32 2, {{i32\*|ptr}} %{{.+}}, align 8
+// CHECK: store i32 3, {{i32\*|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, {{i32\*|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, {{i32\*|ptr}} %{{.+}}, align 4
+#[no_mangle]
+pub fn test3(s: &mut S, i: usize) {
+ s.arr[i] = 5;
+}
+
+// CHECK-LABEL: @test4
+// CHECK: store i32 6, {{i32\*|ptr}} %{{.+}}, align 4
+#[no_mangle]
+pub fn test4(s: &mut S) {
+ s.arr = [6; 4];
+}
diff --git a/tests/codegen/issue-58881.rs b/tests/codegen/issue-58881.rs
new file mode 100644
index 000000000..00f8953d9
--- /dev/null
+++ b/tests/codegen/issue-58881.rs
@@ -0,0 +1,21 @@
+// compile-flags: -C no-prepopulate-passes -Copt-level=0
+//
+// only-x86_64
+// ignore-windows
+
+#![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 {{.*}}, {{%Bar\*|ptr}} {{.*}})
+ variadic_fn(0, Foo(0), Bar(0, 0, 0))
+}
diff --git a/tests/codegen/issue-59352.rs b/tests/codegen/issue-59352.rs
new file mode 100644
index 000000000..d271fe027
--- /dev/null
+++ b/tests/codegen/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: -O -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/issue-69101-bounds-check.rs b/tests/codegen/issue-69101-bounds-check.rs
new file mode 100644
index 000000000..a3aca3a29
--- /dev/null
+++ b/tests/codegen/issue-69101-bounds-check.rs
@@ -0,0 +1,44 @@
+// no-system-llvm
+// compile-flags: -O
+// ignore-debug: the debug assertions get in the way
+#![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/issue-73031.rs b/tests/codegen/issue-73031.rs
new file mode 100644
index 000000000..a09c4bcfb
--- /dev/null
+++ b/tests/codegen/issue-73031.rs
@@ -0,0 +1,26 @@
+// compile-flags: -O
+#![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/issue-73338-effecient-cmp.rs b/tests/codegen/issue-73338-effecient-cmp.rs
new file mode 100644
index 000000000..85c2bbfd0
--- /dev/null
+++ b/tests/codegen/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/issue-73396-bounds-check-after-position.rs b/tests/codegen/issue-73396-bounds-check-after-position.rs
new file mode 100644
index 000000000..8d07a67a1
--- /dev/null
+++ b/tests/codegen/issue-73396-bounds-check-after-position.rs
@@ -0,0 +1,77 @@
+// compile-flags: -O
+// ignore-debug: the debug assertions get in the way
+#![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_index_len_fail
+ 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_index_len_fail
+ 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_index_len_fail
+ 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_index_len_fail
+ 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_index_len_fail
+ 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_index_len_fail
+ if let Some(idx) = s.iter().rposition(|b| *b == b'\\') {
+ s[idx]
+ } else {
+ 42
+ }
+}
diff --git a/tests/codegen/issue-73827-bounds-check-index-in-subexpr.rs b/tests/codegen/issue-73827-bounds-check-index-in-subexpr.rs
new file mode 100644
index 000000000..1ad05906e
--- /dev/null
+++ b/tests/codegen/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: -O
+
+#![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/issue-75525-bounds-checks.rs b/tests/codegen/issue-75525-bounds-checks.rs
new file mode 100644
index 000000000..2d363d8f7
--- /dev/null
+++ b/tests/codegen/issue-75525-bounds-checks.rs
@@ -0,0 +1,26 @@
+// Regression test for #75525, verifies that no bounds checks are generated.
+
+// compile-flags: -O
+
+#![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/issue-75546.rs b/tests/codegen/issue-75546.rs
new file mode 100644
index 000000000..470a9e040
--- /dev/null
+++ b/tests/codegen/issue-75546.rs
@@ -0,0 +1,15 @@
+// compile-flags: -O
+#![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/issue-75659.rs b/tests/codegen/issue-75659.rs
new file mode 100644
index 000000000..6bcb59aff
--- /dev/null
+++ b/tests/codegen/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: -O -Zinline-mir=no
+// 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/issue-77812.rs b/tests/codegen/issue-77812.rs
new file mode 100644
index 000000000..4cc824145
--- /dev/null
+++ b/tests/codegen/issue-77812.rs
@@ -0,0 +1,32 @@
+// compile-flags: -O
+#![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 {
+ 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/issue-81408-dllimport-thinlto-windows.rs b/tests/codegen/issue-81408-dllimport-thinlto-windows.rs
new file mode 100644
index 000000000..0b6ab4f7e
--- /dev/null
+++ b/tests/codegen/issue-81408-dllimport-thinlto-windows.rs
@@ -0,0 +1,15 @@
+// compile-flags: -O -C lto=thin -C prefer-dynamic=no
+// only-windows
+// aux-build:static_dllimport_aux.rs
+
+// Test that on Windows, when performing ThinLTO, we do not mark cross-crate static items with
+// dllimport because lld does not fix the symbol names for us.
+
+extern crate static_dllimport_aux;
+
+// CHECK-LABEL: @{{.+}}CROSS_CRATE_STATIC_ITEM{{.+}} =
+// CHECK-SAME: external local_unnamed_addr global %"{{.+}}AtomicPtr
+
+pub fn main() {
+ static_dllimport_aux::memrchr();
+}
diff --git a/tests/codegen/issue-84268.rs b/tests/codegen/issue-84268.rs
new file mode 100644
index 000000000..7ca195447
--- /dev/null
+++ b/tests/codegen/issue-84268.rs
@@ -0,0 +1,23 @@
+// compile-flags: -O --crate-type=rlib
+#![feature(platform_intrinsics, repr_simd)]
+
+extern "platform-intrinsic" {
+ fn simd_fabs<T>(x: T) -> T;
+ fn simd_eq<T, U>(x: T, y: T) -> U;
+}
+
+#[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/issue-85872-multiple-reverse.rs b/tests/codegen/issue-85872-multiple-reverse.rs
new file mode 100644
index 000000000..591a1aca7
--- /dev/null
+++ b/tests/codegen/issue-85872-multiple-reverse.rs
@@ -0,0 +1,20 @@
+// min-llvm-version: 15.0.0
+// compile-flags: -O
+
+#![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/issue-86106.rs b/tests/codegen/issue-86106.rs
new file mode 100644
index 000000000..9ccbcb24f
--- /dev/null
+++ b/tests/codegen/issue-86106.rs
@@ -0,0 +1,62 @@
+// min-llvm-version: 15.0
+// compile-flags: -C opt-level=3 -Z merge-functions=disabled
+
+// The below two functions ensure that both `String::new()` and `"".to_string()`
+// produce the identical code.
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: define 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 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/issue-96274.rs b/tests/codegen/issue-96274.rs
new file mode 100644
index 000000000..28bfcce0d
--- /dev/null
+++ b/tests/codegen/issue-96274.rs
@@ -0,0 +1,17 @@
+// min-llvm-version: 15.0
+// compile-flags: -O
+
+#![crate_type = "lib"]
+#![feature(inline_const)]
+
+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/issue-96497-slice-size-nowrap.rs b/tests/codegen/issue-96497-slice-size-nowrap.rs
new file mode 100644
index 000000000..0413ed6b2
--- /dev/null
+++ b/tests/codegen/issue-96497-slice-size-nowrap.rs
@@ -0,0 +1,29 @@
+// 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: -O
+// min-llvm-version: 15.0
+
+#![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 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;
+}
diff --git a/tests/codegen/issue-98156-const-arg-temp-lifetime.rs b/tests/codegen/issue-98156-const-arg-temp-lifetime.rs
new file mode 100644
index 000000000..12ace5fff
--- /dev/null
+++ b/tests/codegen/issue-98156-const-arg-temp-lifetime.rs
@@ -0,0 +1,27 @@
+// This test checks that temporaries for indirectly-passed arguments get lifetime markers.
+
+// compile-flags: -O -C no-prepopulate-passes -Zmir-opt-level=0
+
+#![crate_type = "lib"]
+
+extern "Rust" {
+ fn f(x: [u8; 1024]);
+}
+
+const A: [u8; 1024] = [0; 1024];
+
+// CHECK-LABEL: @const_arg_indirect
+#[no_mangle]
+pub unsafe fn const_arg_indirect() {
+ // Ensure that the live ranges for the two argument temporaries don't overlap.
+
+ // CHECK: call void @llvm.lifetime.start
+ // CHECK: call void @f
+ // CHECK: call void @llvm.lifetime.end
+ // CHECK: call void @llvm.lifetime.start
+ // CHECK: call void @f
+ // CHECK: call void @llvm.lifetime.end
+
+ f(A);
+ f(A);
+}
diff --git a/tests/codegen/issue-98294-get-mut-copy-from-slice-opt.rs b/tests/codegen/issue-98294-get-mut-copy-from-slice-opt.rs
new file mode 100644
index 000000000..7da29cd79
--- /dev/null
+++ b/tests/codegen/issue-98294-get-mut-copy-from-slice-opt.rs
@@ -0,0 +1,19 @@
+// min-llvm-version: 15.0.0
+// ignore-debug: The debug assertions get in the way
+// compile-flags: -O
+
+#![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/iter-repeat-n-trivial-drop.rs b/tests/codegen/iter-repeat-n-trivial-drop.rs
new file mode 100644
index 000000000..24059f190
--- /dev/null
+++ b/tests/codegen/iter-repeat-n-trivial-drop.rs
@@ -0,0 +1,56 @@
+// compile-flags: -O
+// only-x86_64
+// ignore-debug: the debug assertions get in the way
+
+#![crate_type = "lib"]
+#![feature(iter_repeat_n)]
+
+#[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-NEXT: %[[DEC:.+]] = add i64 %[[COUNT]], -1
+ // CHECK-NEXT: store i64 %[[DEC]]
+ // CHECK-NOT: br
+ // CHECK: %[[VAL:.+]] = load i16
+ // CHECK-NEXT: br label %[[EMPTY]]
+
+ // CHECK: [[EMPTY]]:
+ // CHECK-NOT: br
+ // CHECK: phi i16 [ undef, %start ], [ %[[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 noundef dereferenceable_or_null(1234) ptr @__rust_alloc(i64 noundef 1234, i64 noundef 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
+}
diff --git a/tests/codegen/layout-size-checks.rs b/tests/codegen/layout-size-checks.rs
new file mode 100644
index 000000000..d067cc10a
--- /dev/null
+++ b/tests/codegen/layout-size-checks.rs
@@ -0,0 +1,31 @@
+// compile-flags: -O
+// only-x86_64
+// ignore-debug: the debug assertions get in the way
+
+#![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/lifetime_start_end.rs b/tests/codegen/lifetime_start_end.rs
new file mode 100644
index 000000000..471a0b8ce
--- /dev/null
+++ b/tests/codegen/lifetime_start_end.rs
@@ -0,0 +1,34 @@
+// compile-flags: -O -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 ]+}}, {{i8\*|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 ]+}}, {{i8\*|ptr}} %c)
+
+// CHECK: call void @llvm.lifetime.end{{.*}}(i{{[0-9 ]+}}, {{i8\*|ptr}} %c)
+
+// CHECK: call void @llvm.lifetime.end{{.*}}(i{{[0-9 ]+}}, {{i8\*|ptr}} %a)
+}
diff --git a/tests/codegen/link-dead-code.rs b/tests/codegen/link-dead-code.rs
new file mode 100644
index 000000000..de5a237c5
--- /dev/null
+++ b/tests/codegen/link-dead-code.rs
@@ -0,0 +1,22 @@
+// 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/link_section.rs b/tests/codegen/link_section.rs
new file mode 100644
index 000000000..88b8692b0
--- /dev/null
+++ b/tests/codegen/link_section.rs
@@ -0,0 +1,35 @@
+// ignore-emscripten default visibility is hidden
+// compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+// CHECK: @VAR1 = constant <{ [4 x i8] }> <{ [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 = constant {{.*}}, section ".test_two"
+#[no_mangle]
+#[link_section = ".test_two"]
+pub static VAR2: E = E::A(666);
+
+// CHECK: @VAR3 = constant {{.*}}, section ".test_three"
+#[no_mangle]
+#[link_section = ".test_three"]
+pub static VAR3: E = E::B(1.);
+
+// CHECK: define void @fn1() {{.*}} section ".test_four" {
+#[no_mangle]
+#[link_section = ".test_four"]
+pub fn fn1() {}
diff --git a/tests/codegen/loads.rs b/tests/codegen/loads.rs
new file mode 100644
index 000000000..f29a26596
--- /dev/null
+++ b/tests/codegen/loads.rs
@@ -0,0 +1,152 @@
+// compile-flags: -C no-prepopulate-passes -Zmir-opt-level=0
+
+#![crate_type = "lib"]
+
+use std::mem::MaybeUninit;
+use std::num::NonZeroU16;
+
+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 {{i32\*|ptr}}, {{i32\*\*|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 {{%Align16\*|i128\*|ptr}}, {{%Align16\*\*|i128\*\*|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 {{i32\*|ptr}}, {{i32\*\*|ptr}} %{{.+}}, align [[PTR_ALIGNMENT]], !nonnull !{{[0-9]+}}, !align ![[ALIGN_4_META]], !noundef !{{[0-9]+}}
+ // CHECK: load {{i64\*|ptr}}, {{i64\*\*|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 {{i32\*|ptr}}, {{i32\*\*|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 {{i32\*|ptr}}, {{i32\*\*|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, {{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, {{i8\*|ptr}} %x, align 1{{$}}
+ *x
+}
+
+// CHECK-LABEL: @load_enum_bool
+#[no_mangle]
+pub fn load_enum_bool(x: &MyBool) -> MyBool {
+ // CHECK: load i8, {{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, {{i8\*|ptr}} %x, align 1{{$}}
+ *x
+}
+
+// CHECK-LABEL: @load_int
+#[no_mangle]
+pub fn load_int(x: &u16) -> u16 {
+ // CHECK: load i16, {{i16\*|ptr}} %x, align 2, !noundef ![[NOUNDEF]]{{$}}
+ *x
+}
+
+// CHECK-LABEL: @load_nonzero_int
+#[no_mangle]
+pub fn load_nonzero_int(x: &NonZeroU16) -> NonZeroU16 {
+ // CHECK: load i16, {{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<NonZeroU16>) -> Option<NonZeroU16> {
+ // CHECK: load i16, {{i16\*|ptr}} %x, align 2, !noundef ![[NOUNDEF]]{{$}}
+ *x
+}
+
+// CHECK-LABEL: @borrow
+#[no_mangle]
+pub fn borrow(x: &i32) -> &i32 {
+ // CHECK: load {{i32\*|ptr}}, {{i32\*\*|ptr}} %x{{.*}}, !nonnull
+ &x; // keep variable in an alloca
+ x
+}
+
+// CHECK-LABEL: @_box
+#[no_mangle]
+pub fn _box(x: Box<i32>) -> i32 {
+ // CHECK: load {{i32\*|ptr}}, {{i32\*\*|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, {{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, {{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/local-generics-in-exe-internalized.rs b/tests/codegen/local-generics-in-exe-internalized.rs
new file mode 100644
index 000000000..e5430fbf1
--- /dev/null
+++ b/tests/codegen/local-generics-in-exe-internalized.rs
@@ -0,0 +1,14 @@
+// compile-flags: -C no-prepopulate-passes -Zshare-generics=yes
+
+// 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/lto-removes-invokes.rs b/tests/codegen/lto-removes-invokes.rs
new file mode 100644
index 000000000..3979a97dc
--- /dev/null
+++ b/tests/codegen/lto-removes-invokes.rs
@@ -0,0 +1,21 @@
+// compile-flags: -C lto -C panic=abort -O
+// 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/mainsubprogram.rs b/tests/codegen/mainsubprogram.rs
new file mode 100644
index 000000000..790db3343
--- /dev/null
+++ b/tests/codegen/mainsubprogram.rs
@@ -0,0 +1,13 @@
+// This test depends on a patch that was committed to upstream LLVM
+// before 4.0, formerly backported to the Rust LLVM fork.
+
+// ignore-windows
+// ignore-macos
+
+// 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/mainsubprogramstart.rs b/tests/codegen/mainsubprogramstart.rs
new file mode 100644
index 000000000..d4de9f59a
--- /dev/null
+++ b/tests/codegen/mainsubprogramstart.rs
@@ -0,0 +1,14 @@
+// ignore-windows
+// ignore-macos
+
+// compile-flags: -g -C no-prepopulate-passes
+
+#![feature(start)]
+
+// CHECK-LABEL: @main
+// CHECK: {{.*}}DISubprogram{{.*}}name: "start",{{.*}}DI{{(SP)?}}FlagMainSubprogram{{.*}}
+
+#[start]
+fn start(_: isize, _: *const *const u8) -> isize {
+ return 0;
+}
diff --git a/tests/codegen/match-optimized.rs b/tests/codegen/match-optimized.rs
new file mode 100644
index 000000000..520c46a0d
--- /dev/null
+++ b/tests/codegen/match-optimized.rs
@@ -0,0 +1,60 @@
+// compile-flags: -C no-prepopulate-passes -O
+
+#![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, {{i8\*|ptr}} %1, align 1
+// CHECK-NEXT: br label %[[EXIT:[a-zA-Z0-9_]+]]
+// CHECK: [[B]]:
+// CHECK-NEXT: store i8 1, {{i8\*|ptr}} %1, align 1
+// CHECK-NEXT: br label %[[EXIT]]
+// CHECK: [[C]]:
+// CHECK-NEXT: store i8 2, {{i8\*|ptr}} %1, align 1
+// CHECK-NEXT: br label %[[EXIT]]
+ match e {
+ E::A => 0,
+ E::B => 1,
+ E::C => 2,
+ }
+}
+
+#[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/match-optimizes-away.rs b/tests/codegen/match-optimizes-away.rs
new file mode 100644
index 000000000..8f66c518c
--- /dev/null
+++ b/tests/codegen/match-optimizes-away.rs
@@ -0,0 +1,34 @@
+//
+// no-system-llvm
+// compile-flags: -O
+#![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: @three_valued
+ // CHECK-NEXT: {{^.*:$}}
+ // CHECK-NEXT: ret i8 %0
+ 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: @four_valued
+ // CHECK-NEXT: {{^.*:$}}
+ // CHECK-NEXT: ret i16 %0
+ match x {
+ Four::A => Four::A,
+ Four::B => Four::B,
+ Four::C => Four::C,
+ Four::D => Four::D,
+ }
+}
diff --git a/tests/codegen/match-unoptimized.rs b/tests/codegen/match-unoptimized.rs
new file mode 100644
index 000000000..78ea4f9b4
--- /dev/null
+++ b/tests/codegen/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/mem-replace-direct-memcpy.rs b/tests/codegen/mem-replace-direct-memcpy.rs
new file mode 100644
index 000000000..e8bbf0e1b
--- /dev/null
+++ b/tests/codegen/mem-replace-direct-memcpy.rs
@@ -0,0 +1,24 @@
+// 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-debug: the debug assertions get in the way
+
+#![crate_type = "lib"]
+
+pub fn replace_byte(dst: &mut u8, src: u8) -> u8 {
+ 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 two direct calls we want, from `ptr::replace`.
+
+// CHECK-NOT: call void @llvm.memcpy
+// CHECK: ; core::mem::replace
+// CHECK-NOT: call void @llvm.memcpy
+// CHECK: call void @llvm.memcpy.{{.+}}({{i8\*|ptr}} align 1 %{{.*}}, {{i8\*|ptr}} align 1 %{{.*}}, i{{.*}} 1, i1 false)
+// CHECK-NOT: call void @llvm.memcpy
+// CHECK: call void @llvm.memcpy.{{.+}}({{i8\*|ptr}} align 1 %{{.*}}, {{i8\*|ptr}} align 1 %{{.*}}, i{{.*}} 1, i1 false)
+// CHECK-NOT: call void @llvm.memcpy
diff --git a/tests/codegen/merge-functions.rs b/tests/codegen/merge-functions.rs
new file mode 100644
index 000000000..8e8fe5c96
--- /dev/null
+++ b/tests/codegen/merge-functions.rs
@@ -0,0 +1,17 @@
+// min-llvm-version: 14.0
+// revisions: O Os
+//[Os] compile-flags: -Copt-level=s
+//[O] compile-flags: -O
+#![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/mir-inlined-line-numbers.rs b/tests/codegen/mir-inlined-line-numbers.rs
new file mode 100644
index 000000000..19d83f0ee
--- /dev/null
+++ b/tests/codegen/mir-inlined-line-numbers.rs
@@ -0,0 +1,25 @@
+// compile-flags: -O -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(), !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/mir_zst_stores.rs b/tests/codegen/mir_zst_stores.rs
new file mode 100644
index 000000000..17e7ba309
--- /dev/null
+++ b/tests/codegen/mir_zst_stores.rs
@@ -0,0 +1,17 @@
+// 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/move-operands.rs b/tests/codegen/move-operands.rs
new file mode 100644
index 000000000..6c51324a3
--- /dev/null
+++ b/tests/codegen/move-operands.rs
@@ -0,0 +1,12 @@
+// compile-flags: -C no-prepopulate-passes -Zmir-enable-passes=+DestinationPropagation
+
+#![crate_type = "lib"]
+
+type T = [u8; 256];
+
+#[no_mangle]
+pub fn f(a: T, b: fn(_: T, _: T)) {
+ // CHECK: call void @llvm.memcpy.{{.*}}({{i8\*|ptr}} align 1 %{{.*}}, {{i8\*|ptr}} align 1 %{{.*}}, {{.*}} 256, i1 false)
+ // CHECK-NOT: call void @llvm.memcpy.{{.*}}({{i8\*|ptr}} align 1 %{{.*}}, {{i8\*|ptr}} align 1 %{{.*}}, {{.*}} 256, i1 false)
+ b(a, a)
+}
diff --git a/tests/codegen/naked-functions.rs b/tests/codegen/naked-functions.rs
new file mode 100644
index 000000000..e05bbc26e
--- /dev/null
+++ b/tests/codegen/naked-functions.rs
@@ -0,0 +1,32 @@
+// compile-flags: -C no-prepopulate-passes -Copt-level=0
+// needs-asm-support
+// only-x86_64
+
+#![crate_type = "lib"]
+#![feature(naked_functions)]
+use std::arch::asm;
+
+// CHECK: Function Attrs: naked
+// CHECK-NEXT: define{{.*}}void @naked_empty()
+#[no_mangle]
+#[naked]
+pub unsafe extern "C" fn naked_empty() {
+ // CHECK-NEXT: {{.+}}:
+ // CHECK-NEXT: call void asm
+ // CHECK-NEXT: unreachable
+ asm!("ret",
+ options(noreturn));
+}
+
+// CHECK: Function Attrs: naked
+// CHECK-NEXT: define{{.*}}i{{[0-9]+}} @naked_with_args_and_return(i64 %a, i64 %b)
+#[no_mangle]
+#[naked]
+pub unsafe extern "C" fn naked_with_args_and_return(a: isize, b: isize) -> isize {
+ // CHECK-NEXT: {{.+}}:
+ // CHECK-NEXT: call void asm
+ // CHECK-NEXT: unreachable
+ asm!("lea rax, [rdi + rsi]",
+ "ret",
+ options(noreturn));
+}
diff --git a/tests/codegen/naked-nocoverage.rs b/tests/codegen/naked-nocoverage.rs
new file mode 100644
index 000000000..91a6260bf
--- /dev/null
+++ b/tests/codegen/naked-nocoverage.rs
@@ -0,0 +1,19 @@
+// Checks that naked functions are not instrumented by -Cinstrument-coverage.
+// Regression test for issue #105170.
+//
+// needs-asm-support
+// needs-profiler-support
+// compile-flags: -Cinstrument-coverage
+#![crate_type = "lib"]
+#![feature(naked_functions)]
+use std::arch::asm;
+
+#[naked]
+#[no_mangle]
+pub unsafe extern "C" fn f() {
+ // CHECK: define void @f()
+ // CHECK-NEXT: start:
+ // CHECK-NEXT: call void asm
+ // CHECK-NEXT: unreachable
+ asm!("", options(noreturn));
+}
diff --git a/tests/codegen/naked-noinline.rs b/tests/codegen/naked-noinline.rs
new file mode 100644
index 000000000..c0ac69f4e
--- /dev/null
+++ b/tests/codegen/naked-noinline.rs
@@ -0,0 +1,31 @@
+// Checks that naked functions are never inlined.
+// compile-flags: -O -Zmir-opt-level=3
+// needs-asm-support
+// ignore-wasm32
+#![crate_type = "lib"]
+#![feature(naked_functions)]
+
+use std::arch::asm;
+
+#[naked]
+#[no_mangle]
+pub unsafe extern "C" fn f() {
+ // Check that f has naked and noinline attributes.
+ //
+ // CHECK: define void @f() unnamed_addr [[ATTR:#[0-9]+]]
+ // CHECK-NEXT: start:
+ // CHECK-NEXT: call void asm
+ asm!("", options(noreturn));
+}
+
+#[no_mangle]
+pub unsafe fn g() {
+ // Check that call to f is not inlined.
+ //
+ // CHECK-LABEL: define void @g()
+ // CHECK-NEXT: start:
+ // CHECK-NEXT: call void @f()
+ f();
+}
+
+// CHECK: attributes [[ATTR]] = { naked{{.*}}noinline{{.*}} }
diff --git a/tests/codegen/no-assumes-on-casts.rs b/tests/codegen/no-assumes-on-casts.rs
new file mode 100644
index 000000000..b5cfa2775
--- /dev/null
+++ b/tests/codegen/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/no-dllimport-w-cross-lang-lto.rs b/tests/codegen/no-dllimport-w-cross-lang-lto.rs
new file mode 100644
index 000000000..33fc2bc15
--- /dev/null
+++ b/tests/codegen/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/no-jump-tables.rs b/tests/codegen/no-jump-tables.rs
new file mode 100644
index 000000000..8e2cb4756
--- /dev/null
+++ b/tests/codegen/no-jump-tables.rs
@@ -0,0 +1,22 @@
+// Test that the `no-jump-tables` function attribute are (not) emitted when
+// the `-Zno-jump-tables` flag is (not) set.
+
+// 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]
+
+#[lang = "sized"]
+trait Sized {}
+
+#[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/no-plt.rs b/tests/codegen/no-plt.rs
new file mode 100644
index 000000000..b36e9ae88
--- /dev/null
+++ b/tests/codegen/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/noalias-box-off.rs b/tests/codegen/noalias-box-off.rs
new file mode 100644
index 000000000..afd17c7c1
--- /dev/null
+++ b/tests/codegen/noalias-box-off.rs
@@ -0,0 +1,8 @@
+// compile-flags: -O -Z box-noalias=no
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @box_should_not_have_noalias_if_disabled(
+// CHECK-NOT: noalias
+#[no_mangle]
+pub fn box_should_not_have_noalias_if_disabled(_b: Box<u8>) {}
diff --git a/tests/codegen/noalias-box.rs b/tests/codegen/noalias-box.rs
new file mode 100644
index 000000000..a3d1f093d
--- /dev/null
+++ b/tests/codegen/noalias-box.rs
@@ -0,0 +1,8 @@
+// compile-flags: -O
+
+#![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/noalias-flag.rs b/tests/codegen/noalias-flag.rs
new file mode 100644
index 000000000..a9ec61e28
--- /dev/null
+++ b/tests/codegen/noalias-flag.rs
@@ -0,0 +1,23 @@
+// compile-flags: -O -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/noalias-refcell.rs b/tests/codegen/noalias-refcell.rs
new file mode 100644
index 000000000..dba73937a
--- /dev/null
+++ b/tests/codegen/noalias-refcell.rs
@@ -0,0 +1,14 @@
+// compile-flags: -O -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/noalias-rwlockreadguard.rs b/tests/codegen/noalias-rwlockreadguard.rs
new file mode 100644
index 000000000..7f7b46c85
--- /dev/null
+++ b/tests/codegen/noalias-rwlockreadguard.rs
@@ -0,0 +1,14 @@
+// compile-flags: -O -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/noalias-unpin.rs b/tests/codegen/noalias-unpin.rs
new file mode 100644
index 000000000..8ca9b98ee
--- /dev/null
+++ b/tests/codegen/noalias-unpin.rs
@@ -0,0 +1,15 @@
+// compile-flags: -O -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/non-terminate/infinite-loop-1.rs b/tests/codegen/non-terminate/infinite-loop-1.rs
new file mode 100644
index 000000000..fa9c66b47
--- /dev/null
+++ b/tests/codegen/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/non-terminate/infinite-loop-2.rs b/tests/codegen/non-terminate/infinite-loop-2.rs
new file mode 100644
index 000000000..81d62ab33
--- /dev/null
+++ b/tests/codegen/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/non-terminate/infinite-recursion.rs b/tests/codegen/non-terminate/infinite-recursion.rs
new file mode 100644
index 000000000..6d1f2d4bf
--- /dev/null
+++ b/tests/codegen/non-terminate/infinite-recursion.rs
@@ -0,0 +1,14 @@
+// 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/non-terminate/nonempty-infinite-loop.rs b/tests/codegen/non-terminate/nonempty-infinite-loop.rs
new file mode 100644
index 000000000..5e25e04fc
--- /dev/null
+++ b/tests/codegen/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/noreturn-uninhabited.rs b/tests/codegen/noreturn-uninhabited.rs
new file mode 100644
index 000000000..49f93cf62
--- /dev/null
+++ b/tests/codegen/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/noreturnflag.rs b/tests/codegen/noreturnflag.rs
new file mode 100644
index 000000000..95c100571
--- /dev/null
+++ b/tests/codegen/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/nounwind.rs b/tests/codegen/nounwind.rs
new file mode 100644
index 000000000..f639c60b8
--- /dev/null
+++ b/tests/codegen/nounwind.rs
@@ -0,0 +1,16 @@
+// aux-build:nounwind.rs
+// compile-flags: -C no-prepopulate-passes -C panic=abort -C metadata=a
+// ignore-windows
+// 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/nrvo.rs b/tests/codegen/nrvo.rs
new file mode 100644
index 000000000..fddb0d1fb
--- /dev/null
+++ b/tests/codegen/nrvo.rs
@@ -0,0 +1,17 @@
+// compile-flags: -O
+
+#![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
+ // CHECK-NOT: @llvm.memcpy
+ // CHECK: ret
+ // CHECK-EMPTY
+ let mut buf = [0; 4096];
+ init(&mut buf);
+ buf
+}
diff --git a/tests/codegen/optimize-attr-1.rs b/tests/codegen/optimize-attr-1.rs
new file mode 100644
index 000000000..22abe06e7
--- /dev/null
+++ b/tests/codegen/optimize-attr-1.rs
@@ -0,0 +1,50 @@
+// 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]+]]
+// NO-OPT: ret i32 4
+// SIZE-OPT: ret i32 4
+// SPEEC-OPT: ret i32 4
+#[no_mangle]
+pub fn nothing() -> i32 {
+ 2 + 2
+}
+
+// CHECK-LABEL: define{{.*}}i32 @size
+// CHECK-SAME: [[SIZE_ATTRS:#[0-9]+]]
+// NO-OPT: ret i32 6
+// 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]+]]
+// NO-OPT: ret i32 8
+// SIZE-OPT: ret i32 8
+// SPEED-OPT: ret i32 8
+#[optimize(speed)]
+#[no_mangle]
+pub fn speed() -> i32 {
+ 4 + 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{{.*}}
+
+// SIZE-OPT: attributes [[SPEED_ATTRS]]
+// SIZE-OPT-NOT: minsize
+// SIZE-OPT-NOT: optsize
diff --git a/tests/codegen/option-nonzero-eq.rs b/tests/codegen/option-nonzero-eq.rs
new file mode 100644
index 000000000..598dcc19b
--- /dev/null
+++ b/tests/codegen/option-nonzero-eq.rs
@@ -0,0 +1,34 @@
+// compile-flags: -O -Zmerge-functions=disabled
+
+#![crate_type = "lib"]
+
+extern crate core;
+use core::num::{NonZeroU32, NonZeroI64};
+use core::ptr::NonNull;
+
+// CHECK-lABEL: @non_zero_eq
+#[no_mangle]
+pub fn non_zero_eq(l: Option<NonZeroU32>, r: Option<NonZeroU32>) -> 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<NonZeroI64>, r: Option<NonZeroI64>) -> bool {
+ // CHECK: start:
+ // CHECK-NEXT: icmp eq i64
+ // CHECK-NEXT: ret i1
+ l == r
+}
+
+// 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 {{(i8\*|ptr)}}
+ // CHECK-NEXT: ret i1
+ l == r
+}
diff --git a/tests/codegen/packed.rs b/tests/codegen/packed.rs
new file mode 100644
index 000000000..fd63b4f0a
--- /dev/null
+++ b/tests/codegen/packed.rs
@@ -0,0 +1,153 @@
+//
+// compile-flags: -O -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, {{i32\*|ptr}} %{{.*}}, align 1
+// CHECK: store i32 42, {{i32\*|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, {{i32\*|ptr}} %{{.*}}, align 2
+// CHECK: store i32 42, {{i32\*|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 %Array
+// CHECK: call void %{{.*}}({{%Array\*|ptr}} noalias nocapture noundef sret{{.*}} dereferenceable(32) [[ALLOCA]])
+// CHECK: call void @llvm.memcpy.{{.*}}({{i8\*|ptr}} align 1 %{{.*}}, {{i8\*|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 %Array
+// CHECK: call void %{{.*}}({{%Array\*|ptr}} noalias nocapture noundef sret{{.*}} dereferenceable(32) [[ALLOCA]])
+// CHECK: call void @llvm.memcpy.{{.*}}({{i8\*|ptr}} align 2 %{{.*}}, {{i8\*|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, {{i32\*|ptr}} %{{.+}}, align 1
+// CHECK: store i32 1, {{i32\*|ptr}} %{{.+}}, align 1
+// CHECK: store i32 2, {{i32\*|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, {{i32\*|ptr}} %{{.+}}, align 2
+// CHECK: store i32 1, {{i32\*|ptr}} %{{.+}}, align 2
+// CHECK: store i32 2, {{i32\*|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, {{i32\*|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, {{i32\*|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.{{.*}}({{i8\*|ptr}} align 1 %{{.*}}, {{i8\*|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.{{.*}}({{i8\*|ptr}} align 2 %{{.*}}, {{i8\*|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.{{.*}}({{i8\*|ptr}} align 1 %{{.*}}, {{i8\*|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.{{.*}}({{i8\*|ptr}} align 2 %{{.*}}, {{i8\*|ptr}} align 2 %{{.*}}, i{{[0-9]+}} 8, i1 false)
+ *pair2 = *pair1;
+}
diff --git a/tests/codegen/panic-abort-windows.rs b/tests/codegen/panic-abort-windows.rs
new file mode 100644
index 000000000..2ee29762d
--- /dev/null
+++ b/tests/codegen/panic-abort-windows.rs
@@ -0,0 +1,18 @@
+// This test is for *-windows only.
+// only-windows
+
+// compile-flags: -C no-prepopulate-passes -C panic=abort -O
+
+#![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 fn extern_uwtable() {
+}
diff --git a/tests/codegen/panic-in-drop-abort.rs b/tests/codegen/panic-in-drop-abort.rs
new file mode 100644
index 000000000..7a84484c4
--- /dev/null
+++ b/tests/codegen/panic-in-drop-abort.rs
@@ -0,0 +1,57 @@
+// compile-flags: -Z panic-in-drop=abort -O
+// 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/panic-unwind-default-uwtable.rs b/tests/codegen/panic-unwind-default-uwtable.rs
new file mode 100644
index 000000000..4c85008cf
--- /dev/null
+++ b/tests/codegen/panic-unwind-default-uwtable.rs
@@ -0,0 +1,6 @@
+// compile-flags: -C panic=unwind -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+// CHECK: attributes #{{.*}} uwtable
+pub fn foo() {}
diff --git a/tests/codegen/personality_lifetimes.rs b/tests/codegen/personality_lifetimes.rs
new file mode 100644
index 000000000..2104022f5
--- /dev/null
+++ b/tests/codegen/personality_lifetimes.rs
@@ -0,0 +1,32 @@
+// ignore-msvc
+// ignore-wasm32-bare compiled with panic=abort by default
+
+// compile-flags: -O -C no-prepopulate-passes
+
+#![crate_type="lib"]
+
+struct S;
+
+impl Drop for S {
+ fn drop(&mut self) {
+ }
+}
+
+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 { {{i8\*|ptr}}, i32 }
+ // 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/pgo-counter-bias.rs b/tests/codegen/pgo-counter-bias.rs
new file mode 100644
index 000000000..28caa7f4a
--- /dev/null
+++ b/tests/codegen/pgo-counter-bias.rs
@@ -0,0 +1,10 @@
+// Test that __llvm_profile_counter_bias does not get internalized by lto.
+
+// ignore-macos -runtime-counter-relocation not honored on Mach-O
+// compile-flags: -Cprofile-generate -Cllvm-args=-runtime-counter-relocation -Clto=fat
+// needs-profiler-support
+// no-prefer-dynamic
+
+// CHECK: @__llvm_profile_counter_bias = {{.*}}global
+
+pub fn main() {}
diff --git a/tests/codegen/pgo-instrumentation.rs b/tests/codegen/pgo-instrumentation.rs
new file mode 100644
index 000000000..05c2d2fc0
--- /dev/null
+++ b/tests/codegen/pgo-instrumentation.rs
@@ -0,0 +1,22 @@
+// Test that `-Cprofile-generate` creates expected instrumentation artifacts in LLVM IR.
+
+// needs-profiler-support
+// 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/pic-relocation-model.rs b/tests/codegen/pic-relocation-model.rs
new file mode 100644
index 000000000..518e949ff
--- /dev/null
+++ b/tests/codegen/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/pie-relocation-model.rs b/tests/codegen/pie-relocation-model.rs
new file mode 100644
index 000000000..941cca922
--- /dev/null
+++ b/tests/codegen/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 zeroext 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/refs.rs b/tests/codegen/refs.rs
new file mode 100644
index 000000000..a52897667
--- /dev/null
+++ b/tests/codegen/refs.rs
@@ -0,0 +1,23 @@
+// 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: [[X0:%[0-9]+]] = getelementptr inbounds { {{\[0 x i8\]\*|ptr}}, [[USIZE]] }, {{.*}} %x, i32 0, i32 0
+// CHECK: store {{\[0 x i8\]\*|ptr}} %s.0, {{.*}} [[X0]]
+// CHECK: [[X1:%[0-9]+]] = getelementptr inbounds { {{\[0 x i8\]\*|ptr}}, [[USIZE]] }, {{.*}} %x, i32 0, i32 1
+// CHECK: store [[USIZE]] %s.1, {{.*}} [[X1]]
+
+ let x = &*s;
+ &x; // keep variable in an alloca
+}
diff --git a/tests/codegen/remap_path_prefix/aux_mod.rs b/tests/codegen/remap_path_prefix/aux_mod.rs
new file mode 100644
index 000000000..44cc4bb72
--- /dev/null
+++ b/tests/codegen/remap_path_prefix/aux_mod.rs
@@ -0,0 +1,6 @@
+// ignore-test: this is not a test
+
+#[inline]
+pub fn some_aux_mod_function() -> i32 {
+ 1234
+}
diff --git a/tests/codegen/remap_path_prefix/auxiliary/remap_path_prefix_aux.rs b/tests/codegen/remap_path_prefix/auxiliary/remap_path_prefix_aux.rs
new file mode 100644
index 000000000..887915955
--- /dev/null
+++ b/tests/codegen/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/remap_path_prefix/auxiliary/xcrate-generic.rs b/tests/codegen/remap_path_prefix/auxiliary/xcrate-generic.rs
new file mode 100644
index 000000000..59092dbf6
--- /dev/null
+++ b/tests/codegen/remap_path_prefix/auxiliary/xcrate-generic.rs
@@ -0,0 +1,6 @@
+//
+// 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>() {}
diff --git a/tests/codegen/remap_path_prefix/issue-73167-remap-std.rs b/tests/codegen/remap_path_prefix/issue-73167-remap-std.rs
new file mode 100644
index 000000000..b66abc6be
--- /dev/null
+++ b/tests/codegen/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/remap_path_prefix/main.rs b/tests/codegen/remap_path_prefix/main.rs
new file mode 100644
index 000000000..78ebbccfc
--- /dev/null
+++ b/tests/codegen/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: @alloc2 = private unnamed_addr constant <{ [34 x i8] }> <{ [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/remap_path_prefix/xcrate-generic.rs b/tests/codegen/remap_path_prefix/xcrate-generic.rs
new file mode 100644
index 000000000..7a9d2ca9b
--- /dev/null
+++ b/tests/codegen/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() {
+ 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/repeat-trusted-len.rs b/tests/codegen/repeat-trusted-len.rs
new file mode 100644
index 000000000..87c8fe135
--- /dev/null
+++ b/tests/codegen/repeat-trusted-len.rs
@@ -0,0 +1,20 @@
+// compile-flags: -O
+//
+
+#![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.{{.+}}({{i8\*|ptr}} {{.*}}align 1{{.*}} %{{[0-9]+}}, 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.{{.+}}({{i8\*|ptr}} {{.*}}align 1{{.*}} %{{[0-9]+}}, i8 13, i{{[0-9]+}} 12345, i1 false)
+ iter::repeat_with(|| 13).take(12345).collect()
+}
diff --git a/tests/codegen/repr-transparent-aggregates-1.rs b/tests/codegen/repr-transparent-aggregates-1.rs
new file mode 100644
index 000000000..f733de12b
--- /dev/null
+++ b/tests/codegen/repr-transparent-aggregates-1.rs
@@ -0,0 +1,87 @@
+// compile-flags: -O -C no-prepopulate-passes
+//
+
+// ignore-arm
+// ignore-aarch64
+// ignore-mips
+// ignore-mips64
+// ignore-powerpc
+// ignore-powerpc64
+// ignore-riscv64 see codegen/riscv-abi
+// ignore-s390x
+// ignore-windows
+// See repr-transparent.rs
+
+#![feature(transparent_unions)]
+
+#![crate_type="lib"]
+
+
+#[derive(Clone, Copy)]
+#[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({{%BigS\*|ptr}} [[BIGS_RET_ATTRS1:.*]] sret(%BigS) [[BIGS_RET_ATTRS2:.*]], {{%BigS\*|ptr}} [[BIGS_ARG_ATTRS1:.*]] byval(%BigS) [[BIGS_ARG_ATTRS2:.*]])
+#[no_mangle]
+pub extern "C" fn test_BigS(_: BigS) -> BigS { loop {} }
+
+// CHECK: define{{.*}}void @test_TsBigS({{%TsBigS\*|ptr}} [[BIGS_RET_ATTRS1]] sret(%TsBigS) [[BIGS_RET_ATTRS2]], {{%TsBigS\*|ptr}} [[BIGS_ARG_ATTRS1]] byval(%TsBigS) [[BIGS_ARG_ATTRS2:.*]])
+#[no_mangle]
+pub extern "C" fn test_TsBigS(_: TsBigS) -> TsBigS { loop {} }
+
+// CHECK: define{{.*}}void @test_TuBigS({{%TuBigS\*|ptr}} [[BIGS_RET_ATTRS1]] sret(%TuBigS) [[BIGS_RET_ATTRS2]], {{%TuBigS\*|ptr}} [[BIGS_ARG_ATTRS1]] byval(%TuBigS) [[BIGS_ARG_ATTRS2:.*]])
+#[no_mangle]
+pub extern "C" fn test_TuBigS(_: TuBigS) -> TuBigS { loop {} }
+
+// CHECK: define{{.*}}void @test_TeBigS({{%"TeBigS::Variant"\*|ptr}} [[BIGS_RET_ATTRS1]] sret(%"TeBigS::Variant") [[BIGS_RET_ATTRS2]], {{%"TeBigS::Variant"\*|ptr}} [[BIGS_ARG_ATTRS1]] byval(%"TeBigS::Variant") [[BIGS_ARG_ATTRS2]])
+#[no_mangle]
+pub extern "C" fn test_TeBigS(_: TeBigS) -> TeBigS { loop {} }
+
+
+#[derive(Clone, Copy)]
+#[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({{%BigU\*|ptr}} [[BIGU_RET_ATTRS1:.*]] sret(%BigU) [[BIGU_RET_ATTRS2:.*]], {{%BigU\*|ptr}} [[BIGU_ARG_ATTRS1:.*]] byval(%BigU) [[BIGU_ARG_ATTRS2:.*]])
+#[no_mangle]
+pub extern "C" fn test_BigU(_: BigU) -> BigU { loop {} }
+
+// CHECK: define{{.*}}void @test_TsBigU({{%TsBigU\*|ptr}} [[BIGU_RET_ATTRS1:.*]] sret(%TsBigU) [[BIGU_RET_ATTRS2:.*]], {{%TsBigU\*|ptr}} [[BIGU_ARG_ATTRS1]] byval(%TsBigU) [[BIGU_ARG_ATTRS2]])
+#[no_mangle]
+pub extern "C" fn test_TsBigU(_: TsBigU) -> TsBigU { loop {} }
+
+// CHECK: define{{.*}}void @test_TuBigU({{%TuBigU\*|ptr}} [[BIGU_RET_ATTRS1]] sret(%TuBigU) [[BIGU_RET_ATTRS2:.*]], {{%TuBigU\*|ptr}} [[BIGU_ARG_ATTRS1]] byval(%TuBigU) [[BIGU_ARG_ATTRS2]])
+#[no_mangle]
+pub extern "C" fn test_TuBigU(_: TuBigU) -> TuBigU { loop {} }
+
+// CHECK: define{{.*}}void @test_TeBigU({{%"TeBigU::Variant"\*|ptr}} [[BIGU_RET_ATTRS1]] sret(%"TeBigU::Variant") [[BIGU_RET_ATTRS2:.*]], {{%"TeBigU::Variant"\*|ptr}} [[BIGU_ARG_ATTRS1]] byval(%"TeBigU::Variant") [[BIGU_ARG_ATTRS2]])
+#[no_mangle]
+pub extern "C" fn test_TeBigU(_: TeBigU) -> TeBigU { loop {} }
diff --git a/tests/codegen/repr-transparent-aggregates-2.rs b/tests/codegen/repr-transparent-aggregates-2.rs
new file mode 100644
index 000000000..df7e88f08
--- /dev/null
+++ b/tests/codegen/repr-transparent-aggregates-2.rs
@@ -0,0 +1,90 @@
+// compile-flags: -C no-prepopulate-passes
+//
+
+// ignore-aarch64
+// ignore-emscripten
+// ignore-mips64
+// ignore-powerpc
+// ignore-powerpc64
+// ignore-powerpc64le
+// ignore-riscv64 see codegen/riscv-abi
+// ignore-s390x
+// ignore-sparc
+// ignore-sparc64
+// ignore-x86
+// ignore-x86_64
+// See repr-transparent.rs
+
+#![feature(transparent_unions)]
+
+#![crate_type="lib"]
+
+
+#[derive(Clone, Copy)]
+#[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({{%BigS\*|ptr}} [[BIGS_RET_ATTRS1:.*]] sret(%BigS) [[BIGS_RET_ATTRS2:.*]], [16 x i32]
+#[no_mangle]
+pub extern fn test_BigS(_: BigS) -> BigS { loop {} }
+
+// CHECK: define void @test_TsBigS({{%TsBigS\*|ptr}} [[BIGS_RET_ATTRS1]] sret(%TsBigS) [[BIGS_RET_ATTRS2]], [16 x i32]
+#[no_mangle]
+pub extern fn test_TsBigS(_: TsBigS) -> TsBigS { loop {} }
+
+// CHECK: define void @test_TuBigS({{%TuBigS\*|ptr}} [[BIGS_RET_ATTRS1]] sret(%TuBigS) [[BIGS_RET_ATTRS2]], [16 x i32]
+#[no_mangle]
+pub extern fn test_TuBigS(_: TuBigS) -> TuBigS { loop {} }
+
+// CHECK: define void @test_TeBigS({{%"TeBigS::Variant"\*|ptr}} [[BIGS_RET_ATTRS1]] sret(%"TeBigS::Variant") [[BIGS_RET_ATTRS2]], [16 x i32]
+#[no_mangle]
+pub extern fn test_TeBigS(_: TeBigS) -> TeBigS { loop {} }
+
+
+#[derive(Clone, Copy)]
+#[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({{%BigU\*|ptr}} [[BIGU_RET_ATTRS1:.*]] sret(%BigU) [[BIGU_RET_ATTRS2:.*]], [16 x i32]
+#[no_mangle]
+pub extern fn test_BigU(_: BigU) -> BigU { loop {} }
+
+// CHECK: define void @test_TsBigU({{%TsBigU\*|ptr}} [[BIGU_RET_ATTRS1]] sret(%TsBigU) [[BIGU_RET_ATTRS2]], [16 x i32]
+#[no_mangle]
+pub extern fn test_TsBigU(_: TsBigU) -> TsBigU { loop {} }
+
+// CHECK: define void @test_TuBigU({{%TuBigU\*|ptr}} [[BIGU_RET_ATTRS1]] sret(%TuBigU) [[BIGU_RET_ATTRS2]], [16 x i32]
+#[no_mangle]
+pub extern fn test_TuBigU(_: TuBigU) -> TuBigU { loop {} }
+
+// CHECK: define void @test_TeBigU({{%"TeBigU::Variant"\*|ptr}} [[BIGU_RET_ATTRS1]] sret(%"TeBigU::Variant") [[BIGU_RET_ATTRS2]], [16 x i32]
+#[no_mangle]
+pub extern fn test_TeBigU(_: TeBigU) -> TeBigU { loop {} }
diff --git a/tests/codegen/repr-transparent-aggregates-3.rs b/tests/codegen/repr-transparent-aggregates-3.rs
new file mode 100644
index 000000000..0db17e6b1
--- /dev/null
+++ b/tests/codegen/repr-transparent-aggregates-3.rs
@@ -0,0 +1,79 @@
+// compile-flags: -C no-prepopulate-passes
+//
+
+// only-mips64
+// See repr-transparent.rs
+
+#![feature(transparent_unions)]
+
+#![crate_type="lib"]
+
+
+#[derive(Clone, Copy)]
+#[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(%BigS* [[BIGS_RET_ATTRS1:.*]] sret(%BigS) [[BIGS_RET_ATTRS2:.*]], [8 x i64]
+#[no_mangle]
+pub extern fn test_BigS(_: BigS) -> BigS { loop {} }
+
+// CHECK: define void @test_TsBigS(%TsBigS* [[BIGS_RET_ATTRS1]] sret(%TsBigS) [[BIGS_RET_ATTRS2]], [8 x i64]
+#[no_mangle]
+pub extern fn test_TsBigS(_: TsBigS) -> TsBigS { loop {} }
+
+// CHECK: define void @test_TuBigS(%TuBigS* [[BIGS_RET_ATTRS1]] sret(%TuBigS) [[BIGS_RET_ATTRS2]], [8 x i64]
+#[no_mangle]
+pub extern fn test_TuBigS(_: TuBigS) -> TuBigS { loop {} }
+
+// CHECK: define void @test_TeBigS(%"TeBigS::Variant"* [[BIGS_RET_ATTRS1]] sret(%"TeBigS::Variant") [[BIGS_RET_ATTRS2]], [8 x i64]
+#[no_mangle]
+pub extern fn test_TeBigS(_: TeBigS) -> TeBigS { loop {} }
+
+
+#[derive(Clone, Copy)]
+#[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(%BigU* [[BIGU_RET_ATTRS1:.*]] sret(%BigU) [[BIGU_RET_ATTRS2:.*]], [8 x i64]
+#[no_mangle]
+pub extern fn test_BigU(_: BigU) -> BigU { loop {} }
+
+// CHECK: define void @test_TsBigU(%TsBigU* [[BIGU_RET_ATTRS1]] sret(%TsBigU) [[BIGU_RET_ATTRS2]], [8 x i64]
+#[no_mangle]
+pub extern fn test_TsBigU(_: TsBigU) -> TsBigU { loop {} }
+
+// CHECK: define void @test_TuBigU(%TuBigU* [[BIGU_RET_ATTRS1]] sret(%TuBigU) [[BIGU_RET_ATTRS2]], [8 x i64]
+#[no_mangle]
+pub extern fn test_TuBigU(_: TuBigU) -> TuBigU { loop {} }
+
+// CHECK: define void @test_TeBigU(%"TeBigU::Variant"* [[BIGU_RET_ATTRS1]] sret(%"TeBigU::Variant") [[BIGU_RET_ATTRS2]], [8 x i64]
+#[no_mangle]
+pub extern fn test_TeBigU(_: TeBigU) -> TeBigU { loop {} }
diff --git a/tests/codegen/repr-transparent-sysv64.rs b/tests/codegen/repr-transparent-sysv64.rs
new file mode 100644
index 000000000..886b0dd9e
--- /dev/null
+++ b/tests/codegen/repr-transparent-sysv64.rs
@@ -0,0 +1,28 @@
+// only-x86_64
+
+// compile-flags: -C no-prepopulate-passes
+
+#![crate_type="lib"]
+
+#[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/repr-transparent.rs b/tests/codegen/repr-transparent.rs
new file mode 100644
index 000000000..311cbfbaa
--- /dev/null
+++ b/tests/codegen/repr-transparent.rs
@@ -0,0 +1,170 @@
+// compile-flags: -O -C no-prepopulate-passes
+
+// ignore-riscv64 riscv64 has an i128 type used with test_Vector
+// see codegen/riscv-abi for riscv functiona call tests
+// ignore-s390x s390x with default march passes vector types per reference
+
+#![crate_type="lib"]
+#![feature(repr_simd, transparent_unions)]
+
+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{{.*}}{{i8\*|ptr}} @test_Ptr({{i8\*|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]);
+
+// Apparently we use i32* when newtype-unwrapping f32 pointers. Whatever.
+// CHECK: define{{.*}}{{i32\*|ptr}} @test_WithZeroSizedArray({{i32\*|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)?}} i8 @test_Gpz(i8 noundef{{( zeroext)?}} %_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{{.*}}{{i16\*|ptr}} @test_LifetimePhantom({{i16\*|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, f32, f32, f32);
+
+#[repr(transparent)]
+pub struct Vector(f32x4);
+
+// CHECK: define{{.*}}<4 x float> @test_Vector(<4 x float> %_1)
+#[no_mangle]
+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 repr-
+// 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/riscv-abi/call-llvm-intrinsics.rs b/tests/codegen/riscv-abi/call-llvm-intrinsics.rs
new file mode 100644
index 000000000..31a88f2c0
--- /dev/null
+++ b/tests/codegen/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, float* %{{.}}, align 4
+ // CHECK: call float @llvm.sqrt.f32(float %{{.}}
+ sqrt(4.0);
+ }
+}
diff --git a/tests/codegen/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs b/tests/codegen/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs
new file mode 100644
index 000000000..045f01985
--- /dev/null
+++ b/tests/codegen/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs
@@ -0,0 +1,189 @@
+// compile-flags: --target riscv64gc-unknown-linux-gnu -O -C no-prepopulate-passes
+// needs-llvm-components: riscv
+
+#![crate_type = "lib"]
+#![no_core]
+#![feature(no_core, lang_items)]
+#![allow(improper_ctypes)]
+
+#[lang = "sized"]
+trait Sized {}
+#[lang = "copy"]
+trait Copy {}
+impl Copy for bool {}
+impl Copy for i8 {}
+impl Copy for u8 {}
+impl Copy for i32 {}
+impl Copy for i64 {}
+impl Copy for u64 {}
+impl Copy for f32 {}
+impl Copy for f64 {}
+
+// 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({{%Large\*|ptr}} {{.*}}%x)
+#[no_mangle]
+pub extern "C" fn f_agg_large(mut x: Large) {
+}
+
+// CHECK: define void @f_agg_large_ret({{%Large\*|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, {{%Large\*|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({{%Large\*|ptr}} {{.*}}sret{{.*}} %0, i64 noundef %a, i128 %1, i128 %2, 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 {{.*}}, {{%Large\*|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/riscv-abi/riscv64-lp64d-abi.rs b/tests/codegen/riscv-abi/riscv64-lp64d-abi.rs
new file mode 100644
index 000000000..1555acadf
--- /dev/null
+++ b/tests/codegen/riscv-abi/riscv64-lp64d-abi.rs
@@ -0,0 +1,293 @@
+//
+// compile-flags: -C no-prepopulate-passes
+// only-riscv64
+// only-linux
+#![crate_type = "lib"]
+
+// CHECK: define void @f_fpr_tracking(double %0, double %1, double %2, double %3, double %4, double %5, double %6, double %7, i8 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 signext %a, i32 signext %b, i32 signext %c, i32 signext %d, i32 signext %e, i32 signext %f, i32 signext %g, i32 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(%IntDoubleInt* {{.*}}%a)
+#[no_mangle]
+pub extern "C" fn f_int_double_int_s_arg(a: IntDoubleInt) {}
+
+// CHECK: define void @f_ret_int_double_int_s(%IntDoubleInt* {{.*}}sret
+#[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/riscv-abi/riscv64-lp64f-lp64d-abi.rs b/tests/codegen/riscv-abi/riscv64-lp64f-lp64d-abi.rs
new file mode 100644
index 000000000..f08fabed4
--- /dev/null
+++ b/tests/codegen/riscv-abi/riscv64-lp64f-lp64d-abi.rs
@@ -0,0 +1,277 @@
+//
+// compile-flags: -C no-prepopulate-passes
+// only-riscv64
+// only-linux
+#![crate_type = "lib"]
+
+// CHECK: define void @f_fpr_tracking(float %0, float %1, float %2, float %3, float %4, float %5, float %6, float %7, i8 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 signext %a, i32 signext %b, i32 signext %c, i32 signext %d, i32 signext %e, i32 signext %f, i32 signext %g, i32 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/sanitizer-cfi-add-canonical-jump-tables-flag.rs b/tests/codegen/sanitizer-cfi-add-canonical-jump-tables-flag.rs
new file mode 100644
index 000000000..c42fbba74
--- /dev/null
+++ b/tests/codegen/sanitizer-cfi-add-canonical-jump-tables-flag.rs
@@ -0,0 +1,11 @@
+// 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 2, !"CFI Canonical Jump Tables", i32 1}
diff --git a/tests/codegen/sanitizer-cfi-emit-type-checks.rs b/tests/codegen/sanitizer-cfi-emit-type-checks.rs
new file mode 100644
index 000000000..597b867eb
--- /dev/null
+++ b/tests/codegen/sanitizer-cfi-emit-type-checks.rs
@@ -0,0 +1,20 @@
+// 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]+}}
+ // CHECK: start:
+ // CHECK: [[TT:%.+]] = call i1 @llvm.type.test({{i8\*|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-NEXT: br label %bb1
+ // CHECK: type_test.fail:
+ // CHECK-NEXT: call void @llvm.trap()
+ // CHECK-NEXT: unreachable
+ f(arg)
+}
diff --git a/tests/codegen/sanitizer-cfi-emit-type-metadata-id-itanium-cxx-abi.rs b/tests/codegen/sanitizer-cfi-emit-type-metadata-id-itanium-cxx-abi.rs
new file mode 100644
index 000000000..b9c339143
--- /dev/null
+++ b/tests/codegen/sanitizer-cfi-emit-type-metadata-id-itanium-cxx-abi.rs
@@ -0,0 +1,591 @@
+// Verifies that type metadata identifiers for functions are emitted correctly.
+//
+// needs-sanitizer-cfi
+// compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi
+
+#![crate_type="lib"]
+#![allow(dead_code)]
+#![allow(incomplete_features)]
+#![allow(unused_must_use)]
+#![feature(adt_const_params, extern_types, inline_const, type_alias_impl_trait)]
+
+extern crate core;
+use core::ffi::c_void;
+use std::marker::PhantomData;
+
+// User-defined type (structure)
+pub struct Struct1<T> {
+ member1: T,
+}
+
+// User-defined type (enum)
+pub enum Enum1<T> {
+ Variant1(T),
+}
+
+// User-defined type (union)
+pub union Union1<T> {
+ member1: std::mem::ManuallyDrop<T>,
+}
+
+// Extern type
+extern {
+ pub type type1;
+}
+
+// Trait
+pub trait Trait1<T> {
+ fn foo(&self) { }
+}
+
+// Trait implementation
+impl<T> Trait1<T> for i32 {
+ fn foo(&self) { }
+}
+
+// Trait implementation
+impl<T> Trait1<T> for Struct1<T> {
+ fn foo(&self) { }
+}
+
+// impl Trait type aliases for helping with defining other types (see below)
+pub type Type1 = impl Send;
+pub type Type2 = impl Send;
+pub type Type3 = impl Send;
+pub type Type4 = impl Send;
+pub type Type5 = impl Send;
+pub type Type6 = impl Send;
+pub type Type7 = impl Send;
+pub type Type8 = impl Send;
+pub type Type9 = impl Send;
+pub type Type10 = impl Send;
+pub type Type11 = impl Send;
+
+pub fn fn1<'a>() {
+ // Closure
+ let closure1 = || { };
+ let _: Type1 = closure1;
+
+ // Constructor
+ pub struct Foo(i32);
+ let _: Type2 = Foo;
+
+ // Type in extern path
+ extern {
+ fn foo();
+ }
+ let _: Type3 = foo;
+
+ // Type in closure path
+ || {
+ pub struct Foo;
+ let _: Type4 = Foo;
+ };
+
+ // Type in const path
+ const {
+ pub struct Foo;
+ fn foo() -> Type5 { Foo }
+ };
+
+ // Type in impl path
+ impl<T> Struct1<T> {
+ fn foo(&self) { }
+ }
+ let _: Type6 = <Struct1<i32>>::foo;
+
+ // Trait method
+ let _: Type7 = <dyn Trait1<i32>>::foo;
+
+ // Trait method
+ let _: Type8 = <i32 as Trait1<i32>>::foo;
+
+ // Trait method
+ let _: Type9 = <Struct1<i32> as Trait1<i32>>::foo;
+
+ // Const generics
+ pub struct Qux<T, const N: usize>([T; N]);
+ let _: Type10 = Qux([0; 32]);
+
+ // Lifetimes/regions
+ pub struct Quux<'a>(&'a i32);
+ pub struct Quuux<'a, 'b>(&'a i32, &'b Quux<'b>);
+ let _: Type11 = Quuux;
+}
+
+// repr(transparent) user-defined type
+struct Foo(i32);
+
+#[repr(transparent)]
+pub struct Type12 {
+ member1: (),
+ member2: PhantomData<i32>,
+ member3: Foo,
+}
+
+// Self-referencing repr(transparent) user-defined type
+#[repr(transparent)]
+pub struct Type13<'a> {
+ member1: (),
+ member2: PhantomData<i32>,
+ member3: &'a Type13<'a>,
+}
+
+// Helper type to allow `Type14<Bar>` to be a unique ID
+pub struct Bar;
+
+// repr(transparent) parameterized type
+#[repr(transparent)]
+pub struct Type14<T>(T);
+
+pub fn foo0(_: ()) { }
+// CHECK: define{{.*}}foo0{{.*}}!type ![[TYPE0:[0-9]+]]
+pub fn foo1(_: c_void, _: ()) { }
+// CHECK: define{{.*}}foo1{{.*}}!type ![[TYPE1:[0-9]+]]
+pub fn foo2(_: (), _: c_void, _: c_void) { }
+// CHECK: define{{.*}}foo2{{.*}}!type ![[TYPE2:[0-9]+]]
+pub fn foo3(_: *mut c_void) { }
+// CHECK: define{{.*}}foo3{{.*}}!type ![[TYPE3:[0-9]+]]
+pub fn foo4(_: *mut c_void, _: *mut ()) { }
+// CHECK: define{{.*}}foo4{{.*}}!type ![[TYPE4:[0-9]+]]
+pub fn foo5(_: *mut (), _: *mut c_void, _: *mut c_void) { }
+// CHECK: define{{.*}}foo5{{.*}}!type ![[TYPE5:[0-9]+]]
+pub fn foo6(_: *const c_void) { }
+// CHECK: define{{.*}}foo6{{.*}}!type ![[TYPE6:[0-9]+]]
+pub fn foo7(_: *const c_void, _: *const ()) { }
+// CHECK: define{{.*}}foo7{{.*}}!type ![[TYPE7:[0-9]+]]
+pub fn foo8(_: *const (), _: *const c_void, _: *const c_void) { }
+// CHECK: define{{.*}}foo8{{.*}}!type ![[TYPE8:[0-9]+]]
+pub fn foo9(_: bool) { }
+// CHECK: define{{.*}}foo9{{.*}}!type ![[TYPE9:[0-9]+]]
+pub fn foo10(_: bool, _: bool) { }
+// CHECK: define{{.*}}foo10{{.*}}!type ![[TYPE10:[0-9]+]]
+pub fn foo11(_: bool, _: bool, _: bool) { }
+// CHECK: define{{.*}}foo11{{.*}}!type ![[TYPE11:[0-9]+]]
+pub fn foo12(_: i8) { }
+// CHECK: define{{.*}}foo12{{.*}}!type ![[TYPE12:[0-9]+]]
+pub fn foo13(_: i8, _: i8) { }
+// CHECK: define{{.*}}foo13{{.*}}!type ![[TYPE13:[0-9]+]]
+pub fn foo14(_: i8, _: i8, _: i8) { }
+// CHECK: define{{.*}}foo14{{.*}}!type ![[TYPE14:[0-9]+]]
+pub fn foo15(_: i16) { }
+// CHECK: define{{.*}}foo15{{.*}}!type ![[TYPE15:[0-9]+]]
+pub fn foo16(_: i16, _: i16) { }
+// CHECK: define{{.*}}foo16{{.*}}!type ![[TYPE16:[0-9]+]]
+pub fn foo17(_: i16, _: i16, _: i16) { }
+// CHECK: define{{.*}}foo17{{.*}}!type ![[TYPE17:[0-9]+]]
+pub fn foo18(_: i32) { }
+// CHECK: define{{.*}}foo18{{.*}}!type ![[TYPE18:[0-9]+]]
+pub fn foo19(_: i32, _: i32) { }
+// CHECK: define{{.*}}foo19{{.*}}!type ![[TYPE19:[0-9]+]]
+pub fn foo20(_: i32, _: i32, _: i32) { }
+// CHECK: define{{.*}}foo20{{.*}}!type ![[TYPE20:[0-9]+]]
+pub fn foo21(_: i64) { }
+// CHECK: define{{.*}}foo21{{.*}}!type ![[TYPE21:[0-9]+]]
+pub fn foo22(_: i64, _: i64) { }
+// CHECK: define{{.*}}foo22{{.*}}!type ![[TYPE22:[0-9]+]]
+pub fn foo23(_: i64, _: i64, _: i64) { }
+// CHECK: define{{.*}}foo23{{.*}}!type ![[TYPE23:[0-9]+]]
+pub fn foo24(_: i128) { }
+// CHECK: define{{.*}}foo24{{.*}}!type ![[TYPE24:[0-9]+]]
+pub fn foo25(_: i128, _: i128) { }
+// CHECK: define{{.*}}foo25{{.*}}!type ![[TYPE25:[0-9]+]]
+pub fn foo26(_: i128, _: i128, _: i128) { }
+// CHECK: define{{.*}}foo26{{.*}}!type ![[TYPE26:[0-9]+]]
+pub fn foo27(_: isize) { }
+// CHECK: define{{.*}}foo27{{.*}}!type ![[TYPE27:[0-9]+]]
+pub fn foo28(_: isize, _: isize) { }
+// CHECK: define{{.*}}foo28{{.*}}!type ![[TYPE28:[0-9]+]]
+pub fn foo29(_: isize, _: isize, _: isize) { }
+// CHECK: define{{.*}}foo29{{.*}}!type ![[TYPE29:[0-9]+]]
+pub fn foo30(_: u8) { }
+// CHECK: define{{.*}}foo30{{.*}}!type ![[TYPE30:[0-9]+]]
+pub fn foo31(_: u8, _: u8) { }
+// CHECK: define{{.*}}foo31{{.*}}!type ![[TYPE31:[0-9]+]]
+pub fn foo32(_: u8, _: u8, _: u8) { }
+// CHECK: define{{.*}}foo32{{.*}}!type ![[TYPE32:[0-9]+]]
+pub fn foo33(_: u16) { }
+// CHECK: define{{.*}}foo33{{.*}}!type ![[TYPE33:[0-9]+]]
+pub fn foo34(_: u16, _: u16) { }
+// CHECK: define{{.*}}foo34{{.*}}!type ![[TYPE34:[0-9]+]]
+pub fn foo35(_: u16, _: u16, _: u16) { }
+// CHECK: define{{.*}}foo35{{.*}}!type ![[TYPE35:[0-9]+]]
+pub fn foo36(_: u32) { }
+// CHECK: define{{.*}}foo36{{.*}}!type ![[TYPE36:[0-9]+]]
+pub fn foo37(_: u32, _: u32) { }
+// CHECK: define{{.*}}foo37{{.*}}!type ![[TYPE37:[0-9]+]]
+pub fn foo38(_: u32, _: u32, _: u32) { }
+// CHECK: define{{.*}}foo38{{.*}}!type ![[TYPE38:[0-9]+]]
+pub fn foo39(_: u64) { }
+// CHECK: define{{.*}}foo39{{.*}}!type ![[TYPE39:[0-9]+]]
+pub fn foo40(_: u64, _: u64) { }
+// CHECK: define{{.*}}foo40{{.*}}!type ![[TYPE40:[0-9]+]]
+pub fn foo41(_: u64, _: u64, _: u64) { }
+// CHECK: define{{.*}}foo41{{.*}}!type ![[TYPE41:[0-9]+]]
+pub fn foo42(_: u128) { }
+// CHECK: define{{.*}}foo42{{.*}}!type ![[TYPE42:[0-9]+]]
+pub fn foo43(_: u128, _: u128) { }
+// CHECK: define{{.*}}foo43{{.*}}!type ![[TYPE43:[0-9]+]]
+pub fn foo44(_: u128, _: u128, _: u128) { }
+// CHECK: define{{.*}}foo44{{.*}}!type ![[TYPE44:[0-9]+]]
+pub fn foo45(_: usize) { }
+// CHECK: define{{.*}}foo45{{.*}}!type ![[TYPE45:[0-9]+]]
+pub fn foo46(_: usize, _: usize) { }
+// CHECK: define{{.*}}foo46{{.*}}!type ![[TYPE46:[0-9]+]]
+pub fn foo47(_: usize, _: usize, _: usize) { }
+// CHECK: define{{.*}}foo47{{.*}}!type ![[TYPE47:[0-9]+]]
+pub fn foo48(_: f32) { }
+// CHECK: define{{.*}}foo48{{.*}}!type ![[TYPE48:[0-9]+]]
+pub fn foo49(_: f32, _: f32) { }
+// CHECK: define{{.*}}foo49{{.*}}!type ![[TYPE49:[0-9]+]]
+pub fn foo50(_: f32, _: f32, _: f32) { }
+// CHECK: define{{.*}}foo50{{.*}}!type ![[TYPE50:[0-9]+]]
+pub fn foo51(_: f64) { }
+// CHECK: define{{.*}}foo51{{.*}}!type ![[TYPE51:[0-9]+]]
+pub fn foo52(_: f64, _: f64) { }
+// CHECK: define{{.*}}foo52{{.*}}!type ![[TYPE52:[0-9]+]]
+pub fn foo53(_: f64, _: f64, _: f64) { }
+// CHECK: define{{.*}}foo53{{.*}}!type ![[TYPE53:[0-9]+]]
+pub fn foo54(_: char) { }
+// CHECK: define{{.*}}foo54{{.*}}!type ![[TYPE54:[0-9]+]]
+pub fn foo55(_: char, _: char) { }
+// CHECK: define{{.*}}foo55{{.*}}!type ![[TYPE55:[0-9]+]]
+pub fn foo56(_: char, _: char, _: char) { }
+// CHECK: define{{.*}}foo56{{.*}}!type ![[TYPE56:[0-9]+]]
+pub fn foo57(_: &str) { }
+// CHECK: define{{.*}}foo57{{.*}}!type ![[TYPE57:[0-9]+]]
+pub fn foo58(_: &str, _: &str) { }
+// CHECK: define{{.*}}foo58{{.*}}!type ![[TYPE58:[0-9]+]]
+pub fn foo59(_: &str, _: &str, _: &str) { }
+// CHECK: define{{.*}}foo59{{.*}}!type ![[TYPE59:[0-9]+]]
+pub fn foo60(_: (i32, i32)) { }
+// CHECK: define{{.*}}foo60{{.*}}!type ![[TYPE60:[0-9]+]]
+pub fn foo61(_: (i32, i32), _: (i32, i32)) { }
+// CHECK: define{{.*}}foo61{{.*}}!type ![[TYPE61:[0-9]+]]
+pub fn foo62(_: (i32, i32), _: (i32, i32), _: (i32, i32)) { }
+// CHECK: define{{.*}}foo62{{.*}}!type ![[TYPE62:[0-9]+]]
+pub fn foo63(_: [i32; 32]) { }
+// CHECK: define{{.*}}foo63{{.*}}!type ![[TYPE63:[0-9]+]]
+pub fn foo64(_: [i32; 32], _: [i32; 32]) { }
+// CHECK: define{{.*}}foo64{{.*}}!type ![[TYPE64:[0-9]+]]
+pub fn foo65(_: [i32; 32], _: [i32; 32], _: [i32; 32]) { }
+// CHECK: define{{.*}}foo65{{.*}}!type ![[TYPE65:[0-9]+]]
+pub fn foo66(_: &[i32]) { }
+// CHECK: define{{.*}}foo66{{.*}}!type ![[TYPE66:[0-9]+]]
+pub fn foo67(_: &[i32], _: &[i32]) { }
+// CHECK: define{{.*}}foo67{{.*}}!type ![[TYPE67:[0-9]+]]
+pub fn foo68(_: &[i32], _: &[i32], _: &[i32]) { }
+// CHECK: define{{.*}}foo68{{.*}}!type ![[TYPE68:[0-9]+]]
+pub fn foo69(_: &Struct1::<i32>) { }
+// CHECK: define{{.*}}foo69{{.*}}!type ![[TYPE69:[0-9]+]]
+pub fn foo70(_: &Struct1::<i32>, _: &Struct1::<i32>) { }
+// CHECK: define{{.*}}foo70{{.*}}!type ![[TYPE70:[0-9]+]]
+pub fn foo71(_: &Struct1::<i32>, _: &Struct1::<i32>, _: &Struct1::<i32>) { }
+// CHECK: define{{.*}}foo71{{.*}}!type ![[TYPE71:[0-9]+]]
+pub fn foo72(_: &Enum1::<i32>) { }
+// CHECK: define{{.*}}foo72{{.*}}!type ![[TYPE72:[0-9]+]]
+pub fn foo73(_: &Enum1::<i32>, _: &Enum1::<i32>) { }
+// CHECK: define{{.*}}foo73{{.*}}!type ![[TYPE73:[0-9]+]]
+pub fn foo74(_: &Enum1::<i32>, _: &Enum1::<i32>, _: &Enum1::<i32>) { }
+// CHECK: define{{.*}}foo74{{.*}}!type ![[TYPE74:[0-9]+]]
+pub fn foo75(_: &Union1::<i32>) { }
+// CHECK: define{{.*}}foo75{{.*}}!type ![[TYPE75:[0-9]+]]
+pub fn foo76(_: &Union1::<i32>, _: &Union1::<i32>) { }
+// CHECK: define{{.*}}foo76{{.*}}!type ![[TYPE76:[0-9]+]]
+pub fn foo77(_: &Union1::<i32>, _: &Union1::<i32>, _: &Union1::<i32>) { }
+// CHECK: define{{.*}}foo77{{.*}}!type ![[TYPE77:[0-9]+]]
+pub fn foo78(_: *mut type1) { }
+// CHECK: define{{.*}}foo78{{.*}}!type ![[TYPE78:[0-9]+]]
+pub fn foo79(_: *mut type1, _: *mut type1) { }
+// CHECK: define{{.*}}foo79{{.*}}!type ![[TYPE79:[0-9]+]]
+pub fn foo80(_: *mut type1, _: *mut type1, _: *mut type1) { }
+// CHECK: define{{.*}}foo80{{.*}}!type ![[TYPE80:[0-9]+]]
+pub fn foo81(_: &mut i32) { }
+// CHECK: define{{.*}}foo81{{.*}}!type ![[TYPE81:[0-9]+]]
+pub fn foo82(_: &mut i32, _: &i32) { }
+// CHECK: define{{.*}}foo82{{.*}}!type ![[TYPE82:[0-9]+]]
+pub fn foo83(_: &mut i32, _: &i32, _: &i32) { }
+// CHECK: define{{.*}}foo83{{.*}}!type ![[TYPE83:[0-9]+]]
+pub fn foo84(_: &i32) { }
+// CHECK: define{{.*}}foo84{{.*}}!type ![[TYPE84:[0-9]+]]
+pub fn foo85(_: &i32, _: &mut i32) { }
+// CHECK: define{{.*}}foo85{{.*}}!type ![[TYPE85:[0-9]+]]
+pub fn foo86(_: &i32, _: &mut i32, _: &mut i32) { }
+// CHECK: define{{.*}}foo86{{.*}}!type ![[TYPE86:[0-9]+]]
+pub fn foo87(_: *mut i32) { }
+// CHECK: define{{.*}}foo87{{.*}}!type ![[TYPE87:[0-9]+]]
+pub fn foo88(_: *mut i32, _: *const i32) { }
+// CHECK: define{{.*}}foo88{{.*}}!type ![[TYPE88:[0-9]+]]
+pub fn foo89(_: *mut i32, _: *const i32, _: *const i32) { }
+// CHECK: define{{.*}}foo89{{.*}}!type ![[TYPE89:[0-9]+]]
+pub fn foo90(_: *const i32) { }
+// CHECK: define{{.*}}foo90{{.*}}!type ![[TYPE90:[0-9]+]]
+pub fn foo91(_: *const i32, _: *mut i32) { }
+// CHECK: define{{.*}}foo91{{.*}}!type ![[TYPE91:[0-9]+]]
+pub fn foo92(_: *const i32, _: *mut i32, _: *mut i32) { }
+// CHECK: define{{.*}}foo92{{.*}}!type ![[TYPE92:[0-9]+]]
+pub fn foo93(_: fn(i32) -> i32) { }
+// CHECK: define{{.*}}foo93{{.*}}!type ![[TYPE93:[0-9]+]]
+pub fn foo94(_: fn(i32) -> i32, _: fn(i32) -> i32) { }
+// CHECK: define{{.*}}foo94{{.*}}!type ![[TYPE94:[0-9]+]]
+pub fn foo95(_: fn(i32) -> i32, _: fn(i32) -> i32, _: fn(i32) -> i32) { }
+// CHECK: define{{.*}}foo95{{.*}}!type ![[TYPE95:[0-9]+]]
+pub fn foo96(_: &dyn Fn(i32) -> i32) { }
+// CHECK: define{{.*}}foo96{{.*}}!type ![[TYPE96:[0-9]+]]
+pub fn foo97(_: &dyn Fn(i32) -> i32, _: &dyn Fn(i32) -> i32) { }
+// CHECK: define{{.*}}foo97{{.*}}!type ![[TYPE97:[0-9]+]]
+pub fn foo98(_: &dyn Fn(i32) -> i32, _: &dyn Fn(i32) -> i32, _: &dyn Fn(i32) -> i32) { }
+// CHECK: define{{.*}}foo98{{.*}}!type ![[TYPE98:[0-9]+]]
+pub fn foo99(_: &dyn FnMut(i32) -> i32) { }
+// CHECK: define{{.*}}foo99{{.*}}!type ![[TYPE99:[0-9]+]]
+pub fn foo100(_: &dyn FnMut(i32) -> i32, _: &dyn FnMut(i32) -> i32) { }
+// CHECK: define{{.*}}foo100{{.*}}!type ![[TYPE100:[0-9]+]]
+pub fn foo101(_: &dyn FnMut(i32) -> i32, _: &dyn FnMut(i32) -> i32, _: &dyn FnMut(i32) -> i32) { }
+// CHECK: define{{.*}}foo101{{.*}}!type ![[TYPE101:[0-9]+]]
+pub fn foo102(_: &dyn FnOnce(i32) -> i32) { }
+// CHECK: define{{.*}}foo102{{.*}}!type ![[TYPE102:[0-9]+]]
+pub fn foo103(_: &dyn FnOnce(i32) -> i32, _: &dyn FnOnce(i32) -> i32) { }
+// CHECK: define{{.*}}foo103{{.*}}!type ![[TYPE103:[0-9]+]]
+pub fn foo104(_: &dyn FnOnce(i32) -> i32, _: &dyn FnOnce(i32) -> i32, _: &dyn FnOnce(i32) -> i32) {}
+// CHECK: define{{.*}}foo104{{.*}}!type ![[TYPE104:[0-9]+]]
+pub fn foo105(_: &dyn Send) { }
+// CHECK: define{{.*}}foo105{{.*}}!type ![[TYPE105:[0-9]+]]
+pub fn foo106(_: &dyn Send, _: &dyn Send) { }
+// CHECK: define{{.*}}foo106{{.*}}!type ![[TYPE106:[0-9]+]]
+pub fn foo107(_: &dyn Send, _: &dyn Send, _: &dyn Send) { }
+// CHECK: define{{.*}}foo107{{.*}}!type ![[TYPE107:[0-9]+]]
+pub fn foo108(_: Type1) { }
+// CHECK: define{{.*}}foo108{{.*}}!type ![[TYPE108:[0-9]+]]
+pub fn foo109(_: Type1, _: Type1) { }
+// CHECK: define{{.*}}foo109{{.*}}!type ![[TYPE109:[0-9]+]]
+pub fn foo110(_: Type1, _: Type1, _: Type1) { }
+// CHECK: define{{.*}}foo110{{.*}}!type ![[TYPE110:[0-9]+]]
+pub fn foo111(_: Type2) { }
+// CHECK: define{{.*}}foo111{{.*}}!type ![[TYPE111:[0-9]+]]
+pub fn foo112(_: Type2, _: Type2) { }
+// CHECK: define{{.*}}foo112{{.*}}!type ![[TYPE112:[0-9]+]]
+pub fn foo113(_: Type2, _: Type2, _: Type2) { }
+// CHECK: define{{.*}}foo113{{.*}}!type ![[TYPE113:[0-9]+]]
+pub fn foo114(_: Type3) { }
+// CHECK: define{{.*}}foo114{{.*}}!type ![[TYPE114:[0-9]+]]
+pub fn foo115(_: Type3, _: Type3) { }
+// CHECK: define{{.*}}foo115{{.*}}!type ![[TYPE115:[0-9]+]]
+pub fn foo116(_: Type3, _: Type3, _: Type3) { }
+// CHECK: define{{.*}}foo116{{.*}}!type ![[TYPE116:[0-9]+]]
+pub fn foo117(_: Type4) { }
+// CHECK: define{{.*}}foo117{{.*}}!type ![[TYPE117:[0-9]+]]
+pub fn foo118(_: Type4, _: Type4) { }
+// CHECK: define{{.*}}foo118{{.*}}!type ![[TYPE118:[0-9]+]]
+pub fn foo119(_: Type4, _: Type4, _: Type4) { }
+// CHECK: define{{.*}}foo119{{.*}}!type ![[TYPE119:[0-9]+]]
+pub fn foo120(_: Type5) { }
+// CHECK: define{{.*}}foo120{{.*}}!type ![[TYPE120:[0-9]+]]
+pub fn foo121(_: Type5, _: Type5) { }
+// CHECK: define{{.*}}foo121{{.*}}!type ![[TYPE121:[0-9]+]]
+pub fn foo122(_: Type5, _: Type5, _: Type5) { }
+// CHECK: define{{.*}}foo122{{.*}}!type ![[TYPE122:[0-9]+]]
+pub fn foo123(_: Type6) { }
+// CHECK: define{{.*}}foo123{{.*}}!type ![[TYPE123:[0-9]+]]
+pub fn foo124(_: Type6, _: Type6) { }
+// CHECK: define{{.*}}foo124{{.*}}!type ![[TYPE124:[0-9]+]]
+pub fn foo125(_: Type6, _: Type6, _: Type6) { }
+// CHECK: define{{.*}}foo125{{.*}}!type ![[TYPE125:[0-9]+]]
+pub fn foo126(_: Type7) { }
+// CHECK: define{{.*}}foo126{{.*}}!type ![[TYPE126:[0-9]+]]
+pub fn foo127(_: Type7, _: Type7) { }
+// CHECK: define{{.*}}foo127{{.*}}!type ![[TYPE127:[0-9]+]]
+pub fn foo128(_: Type7, _: Type7, _: Type7) { }
+// CHECK: define{{.*}}foo128{{.*}}!type ![[TYPE128:[0-9]+]]
+pub fn foo129(_: Type8) { }
+// CHECK: define{{.*}}foo129{{.*}}!type ![[TYPE129:[0-9]+]]
+pub fn foo130(_: Type8, _: Type8) { }
+// CHECK: define{{.*}}foo130{{.*}}!type ![[TYPE130:[0-9]+]]
+pub fn foo131(_: Type8, _: Type8, _: Type8) { }
+// CHECK: define{{.*}}foo131{{.*}}!type ![[TYPE131:[0-9]+]]
+pub fn foo132(_: Type9) { }
+// CHECK: define{{.*}}foo132{{.*}}!type ![[TYPE132:[0-9]+]]
+pub fn foo133(_: Type9, _: Type9) { }
+// CHECK: define{{.*}}foo133{{.*}}!type ![[TYPE133:[0-9]+]]
+pub fn foo134(_: Type9, _: Type9, _: Type9) { }
+// CHECK: define{{.*}}foo134{{.*}}!type ![[TYPE134:[0-9]+]]
+pub fn foo135(_: Type10) { }
+// CHECK: define{{.*}}foo135{{.*}}!type ![[TYPE135:[0-9]+]]
+pub fn foo136(_: Type10, _: Type10) { }
+// CHECK: define{{.*}}foo136{{.*}}!type ![[TYPE136:[0-9]+]]
+pub fn foo137(_: Type10, _: Type10, _: Type10) { }
+// CHECK: define{{.*}}foo137{{.*}}!type ![[TYPE137:[0-9]+]]
+pub fn foo138(_: Type11) { }
+// CHECK: define{{.*}}foo138{{.*}}!type ![[TYPE138:[0-9]+]]
+pub fn foo139(_: Type11, _: Type11) { }
+// CHECK: define{{.*}}foo139{{.*}}!type ![[TYPE139:[0-9]+]]
+pub fn foo140(_: Type11, _: Type11, _: Type11) { }
+// CHECK: define{{.*}}foo140{{.*}}!type ![[TYPE140:[0-9]+]]
+pub fn foo141(_: Type12) { }
+// CHECK: define{{.*}}foo141{{.*}}!type ![[TYPE141:[0-9]+]]
+pub fn foo142(_: Type12, _: Type12) { }
+// CHECK: define{{.*}}foo142{{.*}}!type ![[TYPE142:[0-9]+]]
+pub fn foo143(_: Type12, _: Type12, _: Type12) { }
+// CHECK: define{{.*}}foo143{{.*}}!type ![[TYPE143:[0-9]+]]
+pub fn foo144(_: Type13) { }
+// CHECK: define{{.*}}foo144{{.*}}!type ![[TYPE144:[0-9]+]]
+pub fn foo145(_: Type13, _: Type13) { }
+// CHECK: define{{.*}}foo145{{.*}}!type ![[TYPE145:[0-9]+]]
+pub fn foo146(_: Type13, _: Type13, _: Type13) { }
+// CHECK: define{{.*}}foo146{{.*}}!type ![[TYPE146:[0-9]+]]
+pub fn foo147(_: Type14<Bar>) { }
+// CHECK: define{{.*}}foo147{{.*}}!type ![[TYPE147:[0-9]+]]
+pub fn foo148(_: Type14<Bar>, _: Type14<Bar>) { }
+// CHECK: define{{.*}}foo148{{.*}}!type ![[TYPE148:[0-9]+]]
+pub fn foo149(_: Type14<Bar>, _: Type14<Bar>, _: Type14<Bar>) { }
+// CHECK: define{{.*}}foo149{{.*}}!type ![[TYPE149:[0-9]+]]
+
+// CHECK: ![[TYPE0]] = !{i64 0, !"_ZTSFvvE"}
+// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvvvE"}
+// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvvvvE"}
+// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvPvE"}
+// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvPvS_E"}
+// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvPvS_S_E"}
+// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvPKvE"}
+// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvPKvS0_E"}
+// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvPKvS0_S0_E"}
+// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvbE"}
+// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvbbE"}
+// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvbbbE"}
+// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvu2i8E"}
+// CHECK: ![[TYPE13]] = !{i64 0, !"_ZTSFvu2i8S_E"}
+// CHECK: ![[TYPE14]] = !{i64 0, !"_ZTSFvu2i8S_S_E"}
+// CHECK: ![[TYPE15]] = !{i64 0, !"_ZTSFvu3i16E"}
+// CHECK: ![[TYPE16]] = !{i64 0, !"_ZTSFvu3i16S_E"}
+// CHECK: ![[TYPE17]] = !{i64 0, !"_ZTSFvu3i16S_S_E"}
+// CHECK: ![[TYPE18]] = !{i64 0, !"_ZTSFvu3i32E"}
+// CHECK: ![[TYPE19]] = !{i64 0, !"_ZTSFvu3i32S_E"}
+// CHECK: ![[TYPE20]] = !{i64 0, !"_ZTSFvu3i32S_S_E"}
+// CHECK: ![[TYPE21]] = !{i64 0, !"_ZTSFvu3i64E"}
+// CHECK: ![[TYPE22]] = !{i64 0, !"_ZTSFvu3i64S_E"}
+// CHECK: ![[TYPE23]] = !{i64 0, !"_ZTSFvu3i64S_S_E"}
+// CHECK: ![[TYPE24]] = !{i64 0, !"_ZTSFvu4i128E"}
+// CHECK: ![[TYPE25]] = !{i64 0, !"_ZTSFvu4i128S_E"}
+// CHECK: ![[TYPE26]] = !{i64 0, !"_ZTSFvu4i128S_S_E"}
+// CHECK: ![[TYPE27]] = !{i64 0, !"_ZTSFvu5isizeE"}
+// CHECK: ![[TYPE28]] = !{i64 0, !"_ZTSFvu5isizeS_E"}
+// CHECK: ![[TYPE29]] = !{i64 0, !"_ZTSFvu5isizeS_S_E"}
+// CHECK: ![[TYPE30]] = !{i64 0, !"_ZTSFvu2u8E"}
+// CHECK: ![[TYPE31]] = !{i64 0, !"_ZTSFvu2u8S_E"}
+// CHECK: ![[TYPE32]] = !{i64 0, !"_ZTSFvu2u8S_S_E"}
+// CHECK: ![[TYPE33]] = !{i64 0, !"_ZTSFvu3u16E"}
+// CHECK: ![[TYPE34]] = !{i64 0, !"_ZTSFvu3u16S_E"}
+// CHECK: ![[TYPE35]] = !{i64 0, !"_ZTSFvu3u16S_S_E"}
+// CHECK: ![[TYPE36]] = !{i64 0, !"_ZTSFvu3u32E"}
+// CHECK: ![[TYPE37]] = !{i64 0, !"_ZTSFvu3u32S_E"}
+// CHECK: ![[TYPE38]] = !{i64 0, !"_ZTSFvu3u32S_S_E"}
+// CHECK: ![[TYPE39]] = !{i64 0, !"_ZTSFvu3u64E"}
+// CHECK: ![[TYPE40]] = !{i64 0, !"_ZTSFvu3u64S_E"}
+// CHECK: ![[TYPE41]] = !{i64 0, !"_ZTSFvu3u64S_S_E"}
+// CHECK: ![[TYPE42]] = !{i64 0, !"_ZTSFvu4u128E"}
+// CHECK: ![[TYPE43]] = !{i64 0, !"_ZTSFvu4u128S_E"}
+// CHECK: ![[TYPE44]] = !{i64 0, !"_ZTSFvu4u128S_S_E"}
+// CHECK: ![[TYPE45]] = !{i64 0, !"_ZTSFvu5usizeE"}
+// CHECK: ![[TYPE46]] = !{i64 0, !"_ZTSFvu5usizeS_E"}
+// CHECK: ![[TYPE47]] = !{i64 0, !"_ZTSFvu5usizeS_S_E"}
+// CHECK: ![[TYPE48]] = !{i64 0, !"_ZTSFvu3f32E"}
+// CHECK: ![[TYPE49]] = !{i64 0, !"_ZTSFvu3f32S_E"}
+// CHECK: ![[TYPE50]] = !{i64 0, !"_ZTSFvu3f32S_S_E"}
+// CHECK: ![[TYPE51]] = !{i64 0, !"_ZTSFvu3f64E"}
+// CHECK: ![[TYPE52]] = !{i64 0, !"_ZTSFvu3f64S_E"}
+// CHECK: ![[TYPE53]] = !{i64 0, !"_ZTSFvu3f64S_S_E"}
+// CHECK: ![[TYPE54]] = !{i64 0, !"_ZTSFvu4charE"}
+// CHECK: ![[TYPE55]] = !{i64 0, !"_ZTSFvu4charS_E"}
+// CHECK: ![[TYPE56]] = !{i64 0, !"_ZTSFvu4charS_S_E"}
+// CHECK: ![[TYPE57]] = !{i64 0, !"_ZTSFvu3refIu3strEE"}
+// CHECK: ![[TYPE58]] = !{i64 0, !"_ZTSFvu3refIu3strES0_E"}
+// CHECK: ![[TYPE59]] = !{i64 0, !"_ZTSFvu3refIu3strES0_S0_E"}
+// CHECK: ![[TYPE60]] = !{i64 0, !"_ZTSFvu5tupleIu3i32S_EE"}
+// CHECK: ![[TYPE61]] = !{i64 0, !"_ZTSFvu5tupleIu3i32S_ES0_E"}
+// CHECK: ![[TYPE62]] = !{i64 0, !"_ZTSFvu5tupleIu3i32S_ES0_S0_E"}
+// CHECK: ![[TYPE63]] = !{i64 0, !"_ZTSFvA32u3i32E"}
+// CHECK: ![[TYPE64]] = !{i64 0, !"_ZTSFvA32u3i32S0_E"}
+// CHECK: ![[TYPE65]] = !{i64 0, !"_ZTSFvA32u3i32S0_S0_E"}
+// CHECK: ![[TYPE66]] = !{i64 0, !"_ZTSFvu3refIu5sliceIu3i32EEE"}
+// CHECK: ![[TYPE67]] = !{i64 0, !"_ZTSFvu3refIu5sliceIu3i32EES1_E"}
+// CHECK: ![[TYPE68]] = !{i64 0, !"_ZTSFvu3refIu5sliceIu3i32EES1_S1_E"}
+// CHECK: ![[TYPE69]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi7Struct1Iu3i32EEE"}
+// CHECK: ![[TYPE70]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi7Struct1Iu3i32EES1_E"}
+// CHECK: ![[TYPE71]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi7Struct1Iu3i32EES1_S1_E"}
+// CHECK: ![[TYPE72]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi5Enum1Iu3i32EEE"}
+// CHECK: ![[TYPE73]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi5Enum1Iu3i32EES1_E"}
+// CHECK: ![[TYPE74]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi5Enum1Iu3i32EES1_S1_E"}
+// CHECK: ![[TYPE75]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Union1Iu3i32EEE"}
+// CHECK: ![[TYPE76]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Union1Iu3i32EES1_E"}
+// CHECK: ![[TYPE77]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Union1Iu3i32EES1_S1_E"}
+// CHECK: ![[TYPE78]] = !{i64 0, !"_ZTSFvP5type1E"}
+// CHECK: ![[TYPE79]] = !{i64 0, !"_ZTSFvP5type1S0_E"}
+// CHECK: ![[TYPE80]] = !{i64 0, !"_ZTSFvP5type1S0_S0_E"}
+// CHECK: ![[TYPE81]] = !{i64 0, !"_ZTSFvU3mutu3refIu3i32EE"}
+// CHECK: ![[TYPE82]] = !{i64 0, !"_ZTSFvU3mutu3refIu3i32ES0_E"}
+// CHECK: ![[TYPE83]] = !{i64 0, !"_ZTSFvU3mutu3refIu3i32ES0_S0_E"}
+// CHECK: ![[TYPE84]] = !{i64 0, !"_ZTSFvu3refIu3i32EE"}
+// CHECK: ![[TYPE85]] = !{i64 0, !"_ZTSFvu3refIu3i32EU3mutS0_E"}
+// CHECK: ![[TYPE86]] = !{i64 0, !"_ZTSFvu3refIu3i32EU3mutS0_S1_E"}
+// CHECK: ![[TYPE87]] = !{i64 0, !"_ZTSFvPu3i32E"}
+// CHECK: ![[TYPE88]] = !{i64 0, !"_ZTSFvPu3i32PKS_E"}
+// CHECK: ![[TYPE89]] = !{i64 0, !"_ZTSFvPu3i32PKS_S2_E"}
+// CHECK: ![[TYPE90]] = !{i64 0, !"_ZTSFvPKu3i32E"}
+// CHECK: ![[TYPE91]] = !{i64 0, !"_ZTSFvPKu3i32PS_E"}
+// CHECK: ![[TYPE92]] = !{i64 0, !"_ZTSFvPKu3i32PS_S2_E"}
+// CHECK: ![[TYPE93]] = !{i64 0, !"_ZTSFvPFu3i32S_EE"}
+// CHECK: ![[TYPE94]] = !{i64 0, !"_ZTSFvPFu3i32S_ES0_E"}
+// CHECK: ![[TYPE95]] = !{i64 0, !"_ZTSFvPFu3i32S_ES0_S0_E"}
+// CHECK: ![[TYPE96]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEEE"}
+// CHECK: ![[TYPE97]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_E"}
+// CHECK: ![[TYPE98]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_S5_E"}
+// CHECK: ![[TYPE99]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEEE"}
+// CHECK: ![[TYPE100]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_E"}
+// CHECK: ![[TYPE101]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_S5_E"}
+// CHECK: ![[TYPE102]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEEE"}
+// CHECK: ![[TYPE103]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_E"}
+// CHECK: ![[TYPE104]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_S5_E"}
+// CHECK: ![[TYPE105]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEEE"}
+// CHECK: ![[TYPE106]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEES2_E"}
+// CHECK: ![[TYPE107]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEES2_S2_E"}
+// CHECK: ![[TYPE108]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NCNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn111{{[{}][{}]}}closure{{[}][}]}}Iu2i8PFvvEvEE"}
+// CHECK: ![[TYPE109]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NCNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn111{{[{}][{}]}}closure{{[}][}]}}Iu2i8PFvvEvES1_E"}
+// CHECK: ![[TYPE110]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NCNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn111{{[{}][{}]}}closure{{[}][}]}}Iu2i8PFvvEvES1_S1_E"}
+// CHECK: ![[TYPE111]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn13Foo15{{[{}][{}]}}constructor{{[}][}]}}E"}
+// CHECK: ![[TYPE112]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn13Foo15{{[{}][{}]}}constructor{{[}][}]}}S_E"}
+// CHECK: ![[TYPE113]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn13Foo15{{[{}][{}]}}constructor{{[}][}]}}S_S_E"}
+// CHECK: ![[TYPE114]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn110{{[{}][{}]}}extern{{[}][}]}}3fooE"}
+// CHECK: ![[TYPE115]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn110{{[{}][{}]}}extern{{[}][}]}}3fooS_E"}
+// CHECK: ![[TYPE116]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn110{{[{}][{}]}}extern{{[}][}]}}3fooS_S_E"}
+// CHECK: ![[TYPE117]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn1s0_11{{[{}][{}]}}closure{{[}][}]}}3FooE"}
+// CHECK: ![[TYPE118]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn1s0_11{{[{}][{}]}}closure{{[}][}]}}3FooS_E"}
+// CHECK: ![[TYPE119]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn1s0_11{{[{}][{}]}}closure{{[}][}]}}3FooS_S_E"}
+// CHECK: ![[TYPE120]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn112{{[{}][{}]}}constant{{[}][}]}}3FooE"}
+// CHECK: ![[TYPE121]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn112{{[{}][{}]}}constant{{[}][}]}}3FooS_E"}
+// CHECK: ![[TYPE122]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn112{{[{}][{}]}}constant{{[}][}]}}3FooS_S_E"}
+// CHECK: ![[TYPE123]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn18{{[{}][{}]}}impl{{[}][}]}}3fooIu3i32EE"}
+// CHECK: ![[TYPE124]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn18{{[{}][{}]}}impl{{[}][}]}}3fooIu3i32ES0_E"}
+// CHECK: ![[TYPE125]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn18{{[{}][{}]}}impl{{[}][}]}}3fooIu3i32ES0_S0_E"}
+// CHECK: ![[TYPE126]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait1Iu3i32Eu6regionES_EE"}
+// CHECK: ![[TYPE127]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait1Iu3i32Eu6regionES_ES3_E"}
+// CHECK: ![[TYPE128]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait1Iu3i32Eu6regionES_ES3_S3_E"}
+// CHECK: ![[TYPE129]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3i32S_EE"}
+// CHECK: ![[TYPE130]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3i32S_ES0_E"}
+// CHECK: ![[TYPE131]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3i32S_ES0_S0_E"}
+// CHECK: ![[TYPE132]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi7Struct1Iu3i32ES_EE"}
+// CHECK: ![[TYPE133]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi7Struct1Iu3i32ES_ES1_E"}
+// CHECK: ![[TYPE134]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi7Struct1Iu3i32ES_ES1_S1_E"}
+// CHECK: ![[TYPE135]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn13QuxIu3i32Lu5usize32EEE"}
+// CHECK: ![[TYPE136]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn13QuxIu3i32Lu5usize32EES2_E"}
+// CHECK: ![[TYPE137]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn13QuxIu3i32Lu5usize32EES2_S2_E"}
+// CHECK: ![[TYPE138]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn15Quuux15{{[{}][{}]}}constructor{{[}][}]}}Iu6regionS_EE"}
+// CHECK: ![[TYPE139]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn15Quuux15{{[{}][{}]}}constructor{{[}][}]}}Iu6regionS_ES0_E"}
+// CHECK: ![[TYPE140]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn15Quuux15{{[{}][{}]}}constructor{{[}][}]}}Iu6regionS_ES0_S0_E"}
+// CHECK: ![[TYPE141]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3FooE"}
+// CHECK: ![[TYPE142]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3FooS_E"}
+// CHECK: ![[TYPE143]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3FooS_S_E"}
+// CHECK: ![[TYPE144]] = !{i64 0, !"_ZTSFvu3refIvEE"}
+// CHECK: ![[TYPE145]] = !{i64 0, !"_ZTSFvu3refIvES_E"}
+// CHECK: ![[TYPE146]] = !{i64 0, !"_ZTSFvu3refIvES_S_E"}
+// CHECK: ![[TYPE147]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3BarE
+// CHECK: ![[TYPE148]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3BarS_E
+// CHECK: ![[TYPE149]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3BarS_S_E
diff --git a/tests/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi.rs b/tests/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi.rs
new file mode 100644
index 000000000..bafc4c659
--- /dev/null
+++ b/tests/codegen/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]+]]
+ // CHECK: call i1 @llvm.type.test({{i8\*|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]+]]
+ // CHECK: call i1 @llvm.type.test({{i8\*|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]+]]
+ // CHECK: call i1 @llvm.type.test({{i8\*|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/sanitizer-kcfi-add-kcfi-flag.rs b/tests/codegen/sanitizer-kcfi-add-kcfi-flag.rs
new file mode 100644
index 000000000..c2eb852ae
--- /dev/null
+++ b/tests/codegen/sanitizer-kcfi-add-kcfi-flag.rs
@@ -0,0 +1,11 @@
+// Verifies that "kcfi" module flag is added.
+//
+// needs-sanitizer-kcfi
+// compile-flags: -Ctarget-feature=-crt-static -Zsanitizer=kcfi
+
+#![crate_type="lib"]
+
+pub fn foo() {
+}
+
+// CHECK: !{{[0-9]+}} = !{i32 4, !"kcfi", i32 1}
diff --git a/tests/codegen/sanitizer-kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi.rs b/tests/codegen/sanitizer-kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi.rs
new file mode 100644
index 000000000..2537df80a
--- /dev/null
+++ b/tests/codegen/sanitizer-kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi.rs
@@ -0,0 +1,44 @@
+// Verifies that KCFI type metadata for functions are emitted.
+//
+// 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]
+
+#[lang="sized"]
+trait Sized { }
+#[lang="copy"]
+trait Copy { }
+
+impl Copy for i32 {}
+
+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 i32 %f(i32 %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 i32 %f(i32 %arg1, i32 %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 i32 %f(i32 %arg1, i32 %arg2, i32 %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/sanitizer-memory-track-orgins.rs b/tests/codegen/sanitizer-memory-track-orgins.rs
new file mode 100644
index 000000000..4bd50508d
--- /dev/null
+++ b/tests/codegen/sanitizer-memory-track-orgins.rs
@@ -0,0 +1,30 @@
+// 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
+//
+//[MSAN-0] compile-flags: -Zsanitizer=memory
+//[MSAN-1] compile-flags: -Zsanitizer=memory -Zsanitizer-memory-track-origins=1
+//[MSAN-2] compile-flags: -Zsanitizer=memory -Zsanitizer-memory-track-origins
+//[MSAN-1-LTO] compile-flags: -Zsanitizer=memory -Zsanitizer-memory-track-origins=1 -C lto=fat
+//[MSAN-2-LTO] compile-flags: -Zsanitizer=memory -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/sanitizer-no-sanitize-inlining.rs b/tests/codegen/sanitizer-no-sanitize-inlining.rs
new file mode 100644
index 000000000..f4af60bae
--- /dev/null
+++ b/tests/codegen/sanitizer-no-sanitize-inlining.rs
@@ -0,0 +1,30 @@
+// 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
+//[ASAN] compile-flags: -Zsanitizer=address -C opt-level=3 -Z mir-opt-level=4
+//[LSAN] compile-flags: -Zsanitizer=leak -C opt-level=3 -Z mir-opt-level=4
+
+#![crate_type="lib"]
+#![feature(no_sanitize)]
+
+// ASAN-LABEL: define void @test
+// ASAN: call {{.*}} @random_inline
+// ASAN: }
+//
+// LSAN-LABEL: define void @test
+// LSAN-NO: 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/sanitizer-no-sanitize.rs b/tests/codegen/sanitizer-no-sanitize.rs
new file mode 100644
index 000000000..fb9d249da
--- /dev/null
+++ b/tests/codegen/sanitizer-no-sanitize.rs
@@ -0,0 +1,29 @@
+// Verifies that no_sanitize attribute can be used to
+// selectively disable sanitizer instrumentation.
+//
+// needs-sanitizer-address
+// compile-flags: -Zsanitizer=address
+
+#![crate_type="lib"]
+#![feature(no_sanitize)]
+
+// CHECK-LABEL: ; sanitizer_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: ; sanitizer_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/sanitizer-recover.rs b/tests/codegen/sanitizer-recover.rs
new file mode 100644
index 000000000..7b00fcf8e
--- /dev/null
+++ b/tests/codegen/sanitizer-recover.rs
@@ -0,0 +1,49 @@
+// 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
+//
+//[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/sanitizer_memtag_attr_check.rs b/tests/codegen/sanitizer_memtag_attr_check.rs
new file mode 100644
index 000000000..2fd362656
--- /dev/null
+++ b/tests/codegen/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
+
+#![crate_type = "lib"]
+
+// CHECK: ; Function Attrs:{{.*}}sanitize_memtag
+pub fn tagged() {}
+
+// CHECK: attributes #0 = {{.*}}sanitize_memtag
diff --git a/tests/codegen/sanitizer_scs_attr_check.rs b/tests/codegen/sanitizer_scs_attr_check.rs
new file mode 100644
index 000000000..a885d9117
--- /dev/null
+++ b/tests/codegen/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/scalar-pair-bool.rs b/tests/codegen/scalar-pair-bool.rs
new file mode 100644
index 000000000..8e8365b6a
--- /dev/null
+++ b/tests/codegen/scalar-pair-bool.rs
@@ -0,0 +1,45 @@
+// compile-flags: -O
+
+#![crate_type = "lib"]
+
+// CHECK: define{{.*}}{ i8, i8 } @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{{.*}}{ i8, 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, i8 } @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{{.*}}{ i8, i8 } @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/set-discriminant-invalid.rs b/tests/codegen/set-discriminant-invalid.rs
new file mode 100644
index 000000000..bccb9e4c7
--- /dev/null
+++ b/tests/codegen/set-discriminant-invalid.rs
@@ -0,0 +1,43 @@
+// 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 two instructions to make sure we do not match against `trap`
+ // elsewhere in the code.
+ // CHECK-NEXT: load
+ // CHECK-NEXT: ret
+ #[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/simd-intrinsic/simd-intrinsic-float-abs.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-abs.rs
new file mode 100644
index 000000000..e7bb2327a
--- /dev/null
+++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-abs.rs
@@ -0,0 +1,92 @@
+// compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+#![feature(repr_simd, platform_intrinsics)]
+#![allow(non_camel_case_types)]
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x2(pub f32, pub f32);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x4(pub f32, pub f32, pub f32, pub f32);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x8(pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x16(pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32);
+
+extern "platform-intrinsic" {
+ fn simd_fabs<T>(x: T) -> T;
+}
+
+// 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)
+}
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f64x2(pub f64, pub f64);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f64x4(pub f64, pub f64, pub f64, pub f64);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f64x8(pub f64, pub f64, pub f64, pub f64,
+ pub f64, pub f64, pub f64, pub f64);
+
+// 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/simd-intrinsic/simd-intrinsic-float-ceil.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-ceil.rs
new file mode 100644
index 000000000..e33482d75
--- /dev/null
+++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-ceil.rs
@@ -0,0 +1,92 @@
+// compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+#![feature(repr_simd, platform_intrinsics)]
+#![allow(non_camel_case_types)]
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x2(pub f32, pub f32);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x4(pub f32, pub f32, pub f32, pub f32);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x8(pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x16(pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32);
+
+extern "platform-intrinsic" {
+ fn simd_ceil<T>(x: T) -> T;
+}
+
+// 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)
+}
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f64x2(pub f64, pub f64);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f64x4(pub f64, pub f64, pub f64, pub f64);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f64x8(pub f64, pub f64, pub f64, pub f64,
+ pub f64, pub f64, pub f64, pub f64);
+
+// 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/simd-intrinsic/simd-intrinsic-float-cos.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-cos.rs
new file mode 100644
index 000000000..0f52952bc
--- /dev/null
+++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-cos.rs
@@ -0,0 +1,92 @@
+// compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+#![feature(repr_simd, platform_intrinsics)]
+#![allow(non_camel_case_types)]
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x2(pub f32, pub f32);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x4(pub f32, pub f32, pub f32, pub f32);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x8(pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x16(pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32);
+
+extern "platform-intrinsic" {
+ fn simd_fcos<T>(x: T) -> T;
+}
+
+// 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)
+}
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f64x2(pub f64, pub f64);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f64x4(pub f64, pub f64, pub f64, pub f64);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f64x8(pub f64, pub f64, pub f64, pub f64,
+ pub f64, pub f64, pub f64, pub f64);
+
+// 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/simd-intrinsic/simd-intrinsic-float-exp.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-exp.rs
new file mode 100644
index 000000000..1154acf69
--- /dev/null
+++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-exp.rs
@@ -0,0 +1,92 @@
+// compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+#![feature(repr_simd, platform_intrinsics)]
+#![allow(non_camel_case_types)]
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x2(pub f32, pub f32);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x4(pub f32, pub f32, pub f32, pub f32);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x8(pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x16(pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32);
+
+extern "platform-intrinsic" {
+ fn simd_fexp<T>(x: T) -> T;
+}
+
+// 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)
+}
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f64x2(pub f64, pub f64);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f64x4(pub f64, pub f64, pub f64, pub f64);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f64x8(pub f64, pub f64, pub f64, pub f64,
+ pub f64, pub f64, pub f64, pub f64);
+
+// 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/simd-intrinsic/simd-intrinsic-float-exp2.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-exp2.rs
new file mode 100644
index 000000000..929dc9ac8
--- /dev/null
+++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-exp2.rs
@@ -0,0 +1,92 @@
+// compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+#![feature(repr_simd, platform_intrinsics)]
+#![allow(non_camel_case_types)]
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x2(pub f32, pub f32);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x4(pub f32, pub f32, pub f32, pub f32);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x8(pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x16(pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32);
+
+extern "platform-intrinsic" {
+ fn simd_fexp2<T>(x: T) -> T;
+}
+
+// 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)
+}
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f64x2(pub f64, pub f64);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f64x4(pub f64, pub f64, pub f64, pub f64);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f64x8(pub f64, pub f64, pub f64, pub f64,
+ pub f64, pub f64, pub f64, pub f64);
+
+// 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/simd-intrinsic/simd-intrinsic-float-floor.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-floor.rs
new file mode 100644
index 000000000..56ca644f6
--- /dev/null
+++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-floor.rs
@@ -0,0 +1,92 @@
+// compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+#![feature(repr_simd, platform_intrinsics)]
+#![allow(non_camel_case_types)]
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x2(pub f32, pub f32);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x4(pub f32, pub f32, pub f32, pub f32);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x8(pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x16(pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32);
+
+extern "platform-intrinsic" {
+ fn simd_floor<T>(x: T) -> T;
+}
+
+// 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)
+}
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f64x2(pub f64, pub f64);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f64x4(pub f64, pub f64, pub f64, pub f64);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f64x8(pub f64, pub f64, pub f64, pub f64,
+ pub f64, pub f64, pub f64, pub f64);
+
+// 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/simd-intrinsic/simd-intrinsic-float-fma.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-fma.rs
new file mode 100644
index 000000000..fd65cb72b
--- /dev/null
+++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-fma.rs
@@ -0,0 +1,92 @@
+// compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+#![feature(repr_simd, platform_intrinsics)]
+#![allow(non_camel_case_types)]
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x2(pub f32, pub f32);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x4(pub f32, pub f32, pub f32, pub f32);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x8(pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x16(pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32);
+
+extern "platform-intrinsic" {
+ fn simd_fma<T>(x: T, b: T, c: T) -> T;
+}
+
+// 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)
+}
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f64x2(pub f64, pub f64);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f64x4(pub f64, pub f64, pub f64, pub f64);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f64x8(pub f64, pub f64, pub f64, pub f64,
+ pub f64, pub f64, pub f64, pub f64);
+
+// 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/simd-intrinsic/simd-intrinsic-float-fsqrt.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-fsqrt.rs
new file mode 100644
index 000000000..adc191925
--- /dev/null
+++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-fsqrt.rs
@@ -0,0 +1,92 @@
+// compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+#![feature(repr_simd, platform_intrinsics)]
+#![allow(non_camel_case_types)]
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x2(pub f32, pub f32);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x4(pub f32, pub f32, pub f32, pub f32);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x8(pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x16(pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32);
+
+extern "platform-intrinsic" {
+ fn simd_fsqrt<T>(x: T) -> T;
+}
+
+// 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)
+}
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f64x2(pub f64, pub f64);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f64x4(pub f64, pub f64, pub f64, pub f64);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f64x8(pub f64, pub f64, pub f64, pub f64,
+ pub f64, pub f64, pub f64, pub f64);
+
+// 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/simd-intrinsic/simd-intrinsic-float-log.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-log.rs
new file mode 100644
index 000000000..c072519c0
--- /dev/null
+++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-log.rs
@@ -0,0 +1,92 @@
+// compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+#![feature(repr_simd, platform_intrinsics)]
+#![allow(non_camel_case_types)]
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x2(pub f32, pub f32);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x4(pub f32, pub f32, pub f32, pub f32);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x8(pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x16(pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32);
+
+extern "platform-intrinsic" {
+ fn simd_flog<T>(x: T) -> T;
+}
+
+// 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)
+}
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f64x2(pub f64, pub f64);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f64x4(pub f64, pub f64, pub f64, pub f64);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f64x8(pub f64, pub f64, pub f64, pub f64,
+ pub f64, pub f64, pub f64, pub f64);
+
+// 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/simd-intrinsic/simd-intrinsic-float-log10.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-log10.rs
new file mode 100644
index 000000000..5fd648995
--- /dev/null
+++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-log10.rs
@@ -0,0 +1,92 @@
+// compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+#![feature(repr_simd, platform_intrinsics)]
+#![allow(non_camel_case_types)]
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x2(pub f32, pub f32);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x4(pub f32, pub f32, pub f32, pub f32);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x8(pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x16(pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32);
+
+extern "platform-intrinsic" {
+ fn simd_flog10<T>(x: T) -> T;
+}
+
+// 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)
+}
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f64x2(pub f64, pub f64);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f64x4(pub f64, pub f64, pub f64, pub f64);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f64x8(pub f64, pub f64, pub f64, pub f64,
+ pub f64, pub f64, pub f64, pub f64);
+
+// 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/simd-intrinsic/simd-intrinsic-float-log2.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-log2.rs
new file mode 100644
index 000000000..35175f0ca
--- /dev/null
+++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-log2.rs
@@ -0,0 +1,92 @@
+// compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+#![feature(repr_simd, platform_intrinsics)]
+#![allow(non_camel_case_types)]
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x2(pub f32, pub f32);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x4(pub f32, pub f32, pub f32, pub f32);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x8(pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x16(pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32);
+
+extern "platform-intrinsic" {
+ fn simd_flog2<T>(x: T) -> T;
+}
+
+// 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)
+}
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f64x2(pub f64, pub f64);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f64x4(pub f64, pub f64, pub f64, pub f64);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f64x8(pub f64, pub f64, pub f64, pub f64,
+ pub f64, pub f64, pub f64, pub f64);
+
+// 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/simd-intrinsic/simd-intrinsic-float-minmax.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-minmax.rs
new file mode 100644
index 000000000..4e0abed78
--- /dev/null
+++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-minmax.rs
@@ -0,0 +1,29 @@
+// compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+#![feature(repr_simd, platform_intrinsics)]
+#![allow(non_camel_case_types)]
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x4(pub f32, pub f32, pub f32, pub f32);
+
+extern "platform-intrinsic" {
+ fn simd_fmin<T>(x: T, y: T) -> T;
+ fn simd_fmax<T>(x: T, y: T) -> T;
+}
+
+// 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/simd-intrinsic/simd-intrinsic-float-pow.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-pow.rs
new file mode 100644
index 000000000..3b8d611ab
--- /dev/null
+++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-pow.rs
@@ -0,0 +1,92 @@
+// compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+#![feature(repr_simd, platform_intrinsics)]
+#![allow(non_camel_case_types)]
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x2(pub f32, pub f32);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x4(pub f32, pub f32, pub f32, pub f32);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x8(pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x16(pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32);
+
+extern "platform-intrinsic" {
+ fn simd_fpow<T>(x: T, b: T) -> T;
+}
+
+// CHECK-LABEL: @fpow_32x2
+#[no_mangle]
+pub unsafe fn fpow_32x2(a: f32x2, b: f32x2) -> f32x2 {
+ // CHECK: call <2 x float> @llvm.pow.v2f32
+ simd_fpow(a, b)
+}
+
+// CHECK-LABEL: @fpow_32x4
+#[no_mangle]
+pub unsafe fn fpow_32x4(a: f32x4, b: f32x4) -> f32x4 {
+ // CHECK: call <4 x float> @llvm.pow.v4f32
+ simd_fpow(a, b)
+}
+
+// CHECK-LABEL: @fpow_32x8
+#[no_mangle]
+pub unsafe fn fpow_32x8(a: f32x8, b: f32x8) -> f32x8 {
+ // CHECK: call <8 x float> @llvm.pow.v8f32
+ simd_fpow(a, b)
+}
+
+// CHECK-LABEL: @fpow_32x16
+#[no_mangle]
+pub unsafe fn fpow_32x16(a: f32x16, b: f32x16) -> f32x16 {
+ // CHECK: call <16 x float> @llvm.pow.v16f32
+ simd_fpow(a, b)
+}
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f64x2(pub f64, pub f64);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f64x4(pub f64, pub f64, pub f64, pub f64);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f64x8(pub f64, pub f64, pub f64, pub f64,
+ pub f64, pub f64, pub f64, pub f64);
+
+// CHECK-LABEL: @fpow_64x4
+#[no_mangle]
+pub unsafe fn fpow_64x4(a: f64x4, b: f64x4) -> f64x4 {
+ // CHECK: call <4 x double> @llvm.pow.v4f64
+ simd_fpow(a, b)
+}
+
+// CHECK-LABEL: @fpow_64x2
+#[no_mangle]
+pub unsafe fn fpow_64x2(a: f64x2, b: f64x2) -> f64x2 {
+ // CHECK: call <2 x double> @llvm.pow.v2f64
+ simd_fpow(a, b)
+}
+
+// CHECK-LABEL: @fpow_64x8
+#[no_mangle]
+pub unsafe fn fpow_64x8(a: f64x8, b: f64x8) -> f64x8 {
+ // CHECK: call <8 x double> @llvm.pow.v8f64
+ simd_fpow(a, b)
+}
diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-powi.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-powi.rs
new file mode 100644
index 000000000..e80c50c10
--- /dev/null
+++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-powi.rs
@@ -0,0 +1,92 @@
+// compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+#![feature(repr_simd, platform_intrinsics)]
+#![allow(non_camel_case_types)]
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x2(pub f32, pub f32);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x4(pub f32, pub f32, pub f32, pub f32);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x8(pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x16(pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32);
+
+extern "platform-intrinsic" {
+ fn simd_fpowi<T>(x: T, b: i32) -> T;
+}
+
+// CHECK-LABEL: @fpowi_32x2
+#[no_mangle]
+pub unsafe fn fpowi_32x2(a: f32x2, b: i32) -> f32x2 {
+ // CHECK: call <2 x float> @llvm.powi.v2f32
+ simd_fpowi(a, b)
+}
+
+// CHECK-LABEL: @fpowi_32x4
+#[no_mangle]
+pub unsafe fn fpowi_32x4(a: f32x4, b: i32) -> f32x4 {
+ // CHECK: call <4 x float> @llvm.powi.v4f32
+ simd_fpowi(a, b)
+}
+
+// CHECK-LABEL: @fpowi_32x8
+#[no_mangle]
+pub unsafe fn fpowi_32x8(a: f32x8, b: i32) -> f32x8 {
+ // CHECK: call <8 x float> @llvm.powi.v8f32
+ simd_fpowi(a, b)
+}
+
+// CHECK-LABEL: @fpowi_32x16
+#[no_mangle]
+pub unsafe fn fpowi_32x16(a: f32x16, b: i32) -> f32x16 {
+ // CHECK: call <16 x float> @llvm.powi.v16f32
+ simd_fpowi(a, b)
+}
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f64x2(pub f64, pub f64);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f64x4(pub f64, pub f64, pub f64, pub f64);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f64x8(pub f64, pub f64, pub f64, pub f64,
+ pub f64, pub f64, pub f64, pub f64);
+
+// CHECK-LABEL: @fpowi_64x4
+#[no_mangle]
+pub unsafe fn fpowi_64x4(a: f64x4, b: i32) -> f64x4 {
+ // CHECK: call <4 x double> @llvm.powi.v4f64
+ simd_fpowi(a, b)
+}
+
+// CHECK-LABEL: @fpowi_64x2
+#[no_mangle]
+pub unsafe fn fpowi_64x2(a: f64x2, b: i32) -> f64x2 {
+ // CHECK: call <2 x double> @llvm.powi.v2f64
+ simd_fpowi(a, b)
+}
+
+// CHECK-LABEL: @fpowi_64x8
+#[no_mangle]
+pub unsafe fn fpowi_64x8(a: f64x8, b: i32) -> f64x8 {
+ // CHECK: call <8 x double> @llvm.powi.v8f64
+ simd_fpowi(a, b)
+}
diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-sin.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-sin.rs
new file mode 100644
index 000000000..9e3fab49a
--- /dev/null
+++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-sin.rs
@@ -0,0 +1,92 @@
+// compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+#![feature(repr_simd, platform_intrinsics)]
+#![allow(non_camel_case_types)]
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x2(pub f32, pub f32);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x4(pub f32, pub f32, pub f32, pub f32);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x8(pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x16(pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32,
+ pub f32, pub f32, pub f32, pub f32);
+
+extern "platform-intrinsic" {
+ fn simd_fsin<T>(x: T) -> T;
+}
+
+// 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)
+}
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f64x2(pub f64, pub f64);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f64x4(pub f64, pub f64, pub f64, pub f64);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f64x8(pub f64, pub f64, pub f64, pub f64,
+ pub f64, pub f64, pub f64, pub f64);
+
+// 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/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.rs
new file mode 100644
index 000000000..6fb0ceb40
--- /dev/null
+++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.rs
@@ -0,0 +1,692 @@
+// compile-flags: -C no-prepopulate-passes
+//
+
+#![crate_type = "lib"]
+
+#![feature(repr_simd, platform_intrinsics)]
+#![allow(non_camel_case_types)]
+#![deny(unused)]
+
+// signed integer types
+
+#[repr(simd)] #[derive(Copy, Clone)] pub struct i8x2(i8, i8);
+#[repr(simd)] #[derive(Copy, Clone)] pub struct i8x4(i8, i8, i8, i8);
+#[repr(simd)] #[derive(Copy, Clone)] pub struct i8x8(
+ i8, i8, i8, i8, i8, i8, i8, i8,
+);
+#[repr(simd)] #[derive(Copy, Clone)] pub struct i8x16(
+ i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8,
+);
+#[repr(simd)] #[derive(Copy, Clone)] pub struct i8x32(
+ i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8,
+ i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8,
+);
+#[repr(simd)] #[derive(Copy, Clone)] pub struct i8x64(
+ i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8,
+ i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8,
+ i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8,
+ i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8,
+);
+
+#[repr(simd)] #[derive(Copy, Clone)] pub struct i16x2(i16, i16);
+#[repr(simd)] #[derive(Copy, Clone)] pub struct i16x4(i16, i16, i16, i16);
+#[repr(simd)] #[derive(Copy, Clone)] pub struct i16x8(
+ i16, i16, i16, i16, i16, i16, i16, i16,
+);
+#[repr(simd)] #[derive(Copy, Clone)] pub struct i16x16(
+ i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16,
+);
+#[repr(simd)] #[derive(Copy, Clone)] pub struct i16x32(
+ i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16,
+ i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16,
+);
+
+#[repr(simd)] #[derive(Copy, Clone)] pub struct i32x2(i32, i32);
+#[repr(simd)] #[derive(Copy, Clone)] pub struct i32x4(i32, i32, i32, i32);
+#[repr(simd)] #[derive(Copy, Clone)] pub struct i32x8(
+ i32, i32, i32, i32, i32, i32, i32, i32,
+);
+#[repr(simd)] #[derive(Copy, Clone)] pub struct i32x16(
+ i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32,
+);
+
+#[repr(simd)] #[derive(Copy, Clone)] pub struct i64x2(i64, i64);
+#[repr(simd)] #[derive(Copy, Clone)] pub struct i64x4(i64, i64, i64, i64);
+#[repr(simd)] #[derive(Copy, Clone)] pub struct i64x8(
+ i64, i64, i64, i64, i64, i64, i64, i64,
+);
+
+#[repr(simd)] #[derive(Copy, Clone)] pub struct i128x2(i128, i128);
+#[repr(simd)] #[derive(Copy, Clone)] pub struct i128x4(i128, i128, i128, i128);
+
+// unsigned integer types
+
+#[repr(simd)] #[derive(Copy, Clone)] pub struct u8x2(u8, u8);
+#[repr(simd)] #[derive(Copy, Clone)] pub struct u8x4(u8, u8, u8, u8);
+#[repr(simd)] #[derive(Copy, Clone)] pub struct u8x8(
+ u8, u8, u8, u8, u8, u8, u8, u8,
+);
+#[repr(simd)] #[derive(Copy, Clone)] pub struct u8x16(
+ u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8,
+);
+#[repr(simd)] #[derive(Copy, Clone)] pub struct u8x32(
+ u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8,
+ u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8,
+);
+#[repr(simd)] #[derive(Copy, Clone)] pub struct u8x64(
+ u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8,
+ u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8,
+ u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8,
+ u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8,
+);
+
+#[repr(simd)] #[derive(Copy, Clone)] pub struct u16x2(u16, u16);
+#[repr(simd)] #[derive(Copy, Clone)] pub struct u16x4(u16, u16, u16, u16);
+#[repr(simd)] #[derive(Copy, Clone)] pub struct u16x8(
+ u16, u16, u16, u16, u16, u16, u16, u16,
+);
+#[repr(simd)] #[derive(Copy, Clone)] pub struct u16x16(
+ u16, u16, u16, u16, u16, u16, u16, u16, u16, u16, u16, u16, u16, u16, u16, u16,
+);
+#[repr(simd)] #[derive(Copy, Clone)] pub struct u16x32(
+ u16, u16, u16, u16, u16, u16, u16, u16, u16, u16, u16, u16, u16, u16, u16, u16,
+ u16, u16, u16, u16, u16, u16, u16, u16, u16, u16, u16, u16, u16, u16, u16, u16,
+);
+
+#[repr(simd)] #[derive(Copy, Clone)] pub struct u32x2(u32, u32);
+#[repr(simd)] #[derive(Copy, Clone)] pub struct u32x4(u32, u32, u32, u32);
+#[repr(simd)] #[derive(Copy, Clone)] pub struct u32x8(
+ u32, u32, u32, u32, u32, u32, u32, u32,
+);
+#[repr(simd)] #[derive(Copy, Clone)] pub struct u32x16(
+ u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32,
+);
+
+#[repr(simd)] #[derive(Copy, Clone)] pub struct u64x2(u64, u64);
+#[repr(simd)] #[derive(Copy, Clone)] pub struct u64x4(u64, u64, u64, u64);
+#[repr(simd)] #[derive(Copy, Clone)] pub struct u64x8(
+ u64, u64, u64, u64, u64, u64, u64, u64,
+);
+
+#[repr(simd)] #[derive(Copy, Clone)] pub struct u128x2(u128, u128);
+#[repr(simd)] #[derive(Copy, Clone)] pub struct u128x4(u128, u128, u128, u128);
+
+extern "platform-intrinsic" {
+ fn simd_saturating_add<T>(x: T, y: T) -> T;
+ fn simd_saturating_sub<T>(x: T, y: T) -> T;
+}
+
+// NOTE(eddyb) `%{{x|_3}}` 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 `%_3` a vector loaded from that pointer.
+// This is controlled by the target spec option `simd_types_indirect`.
+// The same applies to `%{{y|_4}}` 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|_3}}, <2 x i8> %{{y|_4}})
+ 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|_3}}, <4 x i8> %{{y|_4}})
+ 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|_3}}, <8 x i8> %{{y|_4}})
+ 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|_3}}, <16 x i8> %{{y|_4}})
+ 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|_3}}, <32 x i8> %{{y|_4}})
+ 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|_3}}, <64 x i8> %{{y|_4}})
+ 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|_3}}, <2 x i16> %{{y|_4}})
+ 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|_3}}, <4 x i16> %{{y|_4}})
+ 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|_3}}, <8 x i16> %{{y|_4}})
+ 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|_3}}, <16 x i16> %{{y|_4}})
+ 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|_3}}, <32 x i16> %{{y|_4}})
+ 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|_3}}, <2 x i32> %{{y|_4}})
+ 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|_3}}, <4 x i32> %{{y|_4}})
+ 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|_3}}, <8 x i32> %{{y|_4}})
+ 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|_3}}, <16 x i32> %{{y|_4}})
+ 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|_3}}, <2 x i64> %{{y|_4}})
+ 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|_3}}, <4 x i64> %{{y|_4}})
+ 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|_3}}, <8 x i64> %{{y|_4}})
+ 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|_3}}, <2 x i128> %{{y|_4}})
+ 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|_3}}, <4 x i128> %{{y|_4}})
+ 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|_3}}, <2 x i8> %{{y|_4}})
+ 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|_3}}, <4 x i8> %{{y|_4}})
+ 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|_3}}, <8 x i8> %{{y|_4}})
+ 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|_3}}, <16 x i8> %{{y|_4}})
+ 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|_3}}, <32 x i8> %{{y|_4}})
+ 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|_3}}, <64 x i8> %{{y|_4}})
+ 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|_3}}, <2 x i16> %{{y|_4}})
+ 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|_3}}, <4 x i16> %{{y|_4}})
+ 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|_3}}, <8 x i16> %{{y|_4}})
+ 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|_3}}, <16 x i16> %{{y|_4}})
+ 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|_3}}, <32 x i16> %{{y|_4}})
+ 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|_3}}, <2 x i32> %{{y|_4}})
+ 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|_3}}, <4 x i32> %{{y|_4}})
+ 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|_3}}, <8 x i32> %{{y|_4}})
+ 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|_3}}, <16 x i32> %{{y|_4}})
+ 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|_3}}, <2 x i64> %{{y|_4}})
+ 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|_3}}, <4 x i64> %{{y|_4}})
+ 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|_3}}, <8 x i64> %{{y|_4}})
+ 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|_3}}, <2 x i128> %{{y|_4}})
+ 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|_3}}, <4 x i128> %{{y|_4}})
+ 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|_3}}, <2 x i8> %{{y|_4}})
+ 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|_3}}, <4 x i8> %{{y|_4}})
+ 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|_3}}, <8 x i8> %{{y|_4}})
+ 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|_3}}, <16 x i8> %{{y|_4}})
+ 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|_3}}, <32 x i8> %{{y|_4}})
+ 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|_3}}, <64 x i8> %{{y|_4}})
+ 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|_3}}, <2 x i16> %{{y|_4}})
+ 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|_3}}, <4 x i16> %{{y|_4}})
+ 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|_3}}, <8 x i16> %{{y|_4}})
+ 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|_3}}, <16 x i16> %{{y|_4}})
+ 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|_3}}, <32 x i16> %{{y|_4}})
+ 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|_3}}, <2 x i32> %{{y|_4}})
+ 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|_3}}, <4 x i32> %{{y|_4}})
+ 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|_3}}, <8 x i32> %{{y|_4}})
+ 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|_3}}, <16 x i32> %{{y|_4}})
+ 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|_3}}, <2 x i64> %{{y|_4}})
+ 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|_3}}, <4 x i64> %{{y|_4}})
+ 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|_3}}, <8 x i64> %{{y|_4}})
+ 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|_3}}, <2 x i128> %{{y|_4}})
+ 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|_3}}, <4 x i128> %{{y|_4}})
+ 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|_3}}, <2 x i8> %{{y|_4}})
+ 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|_3}}, <4 x i8> %{{y|_4}})
+ 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|_3}}, <8 x i8> %{{y|_4}})
+ 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|_3}}, <16 x i8> %{{y|_4}})
+ 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|_3}}, <32 x i8> %{{y|_4}})
+ 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|_3}}, <64 x i8> %{{y|_4}})
+ 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|_3}}, <2 x i16> %{{y|_4}})
+ 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|_3}}, <4 x i16> %{{y|_4}})
+ 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|_3}}, <8 x i16> %{{y|_4}})
+ 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|_3}}, <16 x i16> %{{y|_4}})
+ 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|_3}}, <32 x i16> %{{y|_4}})
+ 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|_3}}, <2 x i32> %{{y|_4}})
+ 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|_3}}, <4 x i32> %{{y|_4}})
+ 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|_3}}, <8 x i32> %{{y|_4}})
+ 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|_3}}, <16 x i32> %{{y|_4}})
+ 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|_3}}, <2 x i64> %{{y|_4}})
+ 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|_3}}, <4 x i64> %{{y|_4}})
+ 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|_3}}, <8 x i64> %{{y|_4}})
+ 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|_3}}, <2 x i128> %{{y|_4}})
+ 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|_3}}, <4 x i128> %{{y|_4}})
+ simd_saturating_sub(x, y)
+}
diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-bitmask.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-bitmask.rs
new file mode 100644
index 000000000..4a98d797b
--- /dev/null
+++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-bitmask.rs
@@ -0,0 +1,63 @@
+// compile-flags: -C no-prepopulate-passes
+//
+
+#![crate_type = "lib"]
+
+#![feature(repr_simd, platform_intrinsics)]
+#![allow(non_camel_case_types)]
+
+#[repr(simd)]
+#[derive(Copy, Clone)]
+pub struct u32x2(u32, u32);
+
+#[repr(simd)]
+#[derive(Copy, Clone)]
+pub struct i32x2(i32, i32);
+
+#[repr(simd)]
+#[derive(Copy, Clone)]
+pub struct i8x16(
+ i8, i8, i8, i8, i8, i8, i8, i8,
+ i8, i8, i8, i8, i8, i8, i8, i8,
+);
+
+
+extern "platform-intrinsic" {
+ fn simd_bitmask<T, U>(x: T) -> U;
+}
+
+// NOTE(eddyb) `%{{x|_2}}` 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 `%_2` 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|_2}}, <i32 31, 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|_2}}, <i32 31, 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|_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>
+ // 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/simd-intrinsic/simd-intrinsic-generic-extract-insert.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-extract-insert.rs
new file mode 100644
index 000000000..b5b0b1330
--- /dev/null
+++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-extract-insert.rs
@@ -0,0 +1,47 @@
+// compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+#![feature(repr_simd, platform_intrinsics, min_const_generics)]
+#![allow(non_camel_case_types)]
+
+#[repr(simd)]
+#[derive(Copy, Clone)]
+pub struct M(pub f32, pub f32, pub f32, pub f32);
+
+#[repr(simd)]
+#[derive(Copy, Clone)]
+pub struct S<const N: usize>([f32; N]);
+
+extern "platform-intrinsic" {
+ fn simd_extract<T, U>(x: T, idx: u32) -> U;
+ fn simd_insert<T, U>(x: T, idx: u32, b: U) -> T;
+}
+
+// CHECK-LABEL: @extract_m
+#[no_mangle]
+pub unsafe fn extract_m(v: M, i: u32) -> f32 {
+ // CHECK: extractelement <4 x float> %{{v|_3}}, i32 %i
+ simd_extract(v, i)
+}
+
+// CHECK-LABEL: @extract_s
+#[no_mangle]
+pub unsafe fn extract_s(v: S<4>, i: u32) -> f32 {
+ // CHECK: extractelement <4 x float> %{{v|_3}}, i32 %i
+ simd_extract(v, i)
+}
+
+// CHECK-LABEL: @insert_m
+#[no_mangle]
+pub unsafe fn insert_m(v: M, i: u32, j: f32) -> M {
+ // CHECK: insertelement <4 x float> %{{v|_4}}, float %j, i32 %i
+ simd_insert(v, i, j)
+}
+
+// CHECK-LABEL: @insert_s
+#[no_mangle]
+pub unsafe fn insert_s(v: S<4>, i: u32, j: f32) -> S<4> {
+ // CHECK: insertelement <4 x float> %{{v|_4}}, float %j, i32 %i
+ simd_insert(v, i, j)
+}
diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-gather.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-gather.rs
new file mode 100644
index 000000000..cacc32f2f
--- /dev/null
+++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-gather.rs
@@ -0,0 +1,36 @@
+//
+
+// compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+#![feature(repr_simd, platform_intrinsics)]
+#![allow(non_camel_case_types)]
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct Vec2<T>(pub T, pub T);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct Vec4<T>(pub T, pub T, pub T, pub T);
+
+extern "platform-intrinsic" {
+ fn simd_gather<T, P, M>(value: T, pointers: P, mask: M) -> T;
+}
+
+// CHECK-LABEL: @gather_f32x2
+#[no_mangle]
+pub unsafe fn gather_f32x2(pointers: Vec2<*const f32>, mask: Vec2<i32>,
+ values: Vec2<f32>) -> Vec2<f32> {
+ // CHECK: call <2 x float> @llvm.masked.gather.v2f32.{{.+}}(<2 x {{float\*|ptr}}> {{.*}}, i32 {{.*}}, <2 x i1> {{.*}}, <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: call <2 x {{float\*|ptr}}> @llvm.masked.gather.{{.+}}(<2 x {{float\*\*|ptr}}> {{.*}}, i32 {{.*}}, <2 x i1> {{.*}}, <2 x {{float\*|ptr}}> {{.*}})
+ simd_gather(values, pointers, mask)
+}
diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-scatter.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-scatter.rs
new file mode 100644
index 000000000..94ecaf609
--- /dev/null
+++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-scatter.rs
@@ -0,0 +1,37 @@
+//
+
+// compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+#![feature(repr_simd, platform_intrinsics)]
+#![allow(non_camel_case_types)]
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct Vec2<T>(pub T, pub T);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct Vec4<T>(pub T, pub T, pub T, pub T);
+
+extern "platform-intrinsic" {
+ fn simd_scatter<T, P, M>(value: T, pointers: P, mask: M);
+}
+
+// CHECK-LABEL: @scatter_f32x2
+#[no_mangle]
+pub unsafe fn scatter_f32x2(pointers: Vec2<*mut f32>, mask: Vec2<i32>,
+ values: Vec2<f32>) {
+ // CHECK: call void @llvm.masked.scatter.v2f32.v2p0{{.*}}(<2 x float> {{.*}}, <2 x {{float\*|ptr}}> {{.*}}, i32 {{.*}}, <2 x i1> {{.*}})
+ 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: call void @llvm.masked.scatter.v2p0{{.*}}.v2p0{{.*}}(<2 x {{float\*|ptr}}> {{.*}}, <2 x {{float\*\*|ptr}}> {{.*}}, i32 {{.*}}, <2 x i1> {{.*}})
+ simd_scatter(values, pointers, mask)
+}
diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-select.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-select.rs
new file mode 100644
index 000000000..03bb22655
--- /dev/null
+++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-select.rs
@@ -0,0 +1,37 @@
+// compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+#![feature(repr_simd, platform_intrinsics)]
+#[allow(non_camel_case_types)]
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x4(pub f32, pub f32, pub f32, pub f32);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x8(f32, f32, f32, f32, f32, f32, f32, f32);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct b8x4(pub i8, pub i8, pub i8, pub i8);
+
+extern "platform-intrinsic" {
+ fn simd_select<T, U>(x: T, a: U, b: U) -> U;
+ fn simd_select_bitmask<T, U>(x: T, a: U, b: U) -> U;
+}
+
+// CHECK-LABEL: @select
+#[no_mangle]
+pub unsafe fn select(m: b8x4, a: f32x4, b: f32x4) -> f32x4 {
+ // CHECK: select <4 x i1>
+ simd_select(m, a, b)
+}
+
+// CHECK-LABEL: @select_bitmask
+#[no_mangle]
+pub unsafe fn select_bitmask(m: i8, a: f32x8, b: f32x8) -> f32x8 {
+ // CHECK: select <8 x i1>
+ simd_select_bitmask(m, a, b)
+}
diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs
new file mode 100644
index 000000000..db5b60567
--- /dev/null
+++ b/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs
@@ -0,0 +1,43 @@
+//
+// compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+#![allow(non_camel_case_types)]
+#![feature(repr_simd, platform_intrinsics, min_const_generics)]
+
+#[repr(simd)]
+#[derive(Copy, Clone)]
+pub struct S<const N: usize>([f32; N]);
+
+#[repr(simd)]
+#[derive(Copy, Clone)]
+pub struct T([f32; 4]);
+
+#[repr(simd)]
+#[derive(Copy, Clone)]
+pub struct U(f32, f32, f32, f32);
+
+// CHECK-LABEL: @build_array_s
+#[no_mangle]
+pub fn build_array_s(x: [f32; 4]) -> S<4> {
+ // CHECK: call void @llvm.memcpy.{{.+}}({{.*}}, i{{[0-9]+}} 16, i1 false)
+ // CHECK: call void @llvm.memcpy.{{.+}}({{.*}}, i{{[0-9]+}} 16, i1 false)
+ S::<4>(x)
+}
+
+// CHECK-LABEL: @build_array_t
+#[no_mangle]
+pub fn build_array_t(x: [f32; 4]) -> T {
+ // CHECK: call void @llvm.memcpy.{{.+}}({{.*}}, i{{[0-9]+}} 16, i1 false)
+ // CHECK: call void @llvm.memcpy.{{.+}}({{.*}}, i{{[0-9]+}} 16, i1 false)
+ T(x)
+}
+
+// CHECK-LABEL: @build_array_u
+#[no_mangle]
+pub fn build_array_u(x: [f32; 4]) -> U {
+ // CHECK: call void @llvm.memcpy.{{.+}}({{.*}}, i{{[0-9]+}} 16, i1 false)
+ // CHECK: call void @llvm.memcpy.{{.+}}({{.*}}, i{{[0-9]+}} 16, i1 false)
+ unsafe { std::mem::transmute(x) }
+}
diff --git a/tests/codegen/simd-wide-sum.rs b/tests/codegen/simd-wide-sum.rs
new file mode 100644
index 000000000..04314dc29
--- /dev/null
+++ b/tests/codegen/simd-wide-sum.rs
@@ -0,0 +1,55 @@
+// compile-flags: -C opt-level=3 --edition=2021
+// only-x86_64
+// ignore-debug: the debug assertions get in the way
+
+#![crate_type = "lib"]
+#![feature(portable_simd)]
+
+use std::simd::{Simd, SimdUint};
+const N: usize = 8;
+
+#[no_mangle]
+// CHECK-LABEL: @wider_reduce_simd
+pub fn wider_reduce_simd(x: Simd<u8, N>) -> u16 {
+ // CHECK: zext <8 x i8>
+ // CHECK-SAME: to <8 x i16>
+ // CHECK: call i16 @llvm.vector.reduce.add.v8i16(<8 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 <8 x i8>
+ // CHECK-SAME: to <8 x i16>
+ // CHECK: call i16 @llvm.vector.reduce.add.v8i16(<8 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 <8 x i8>
+ // CHECK-SAME: to <8 x i16>
+ // CHECK: call i16 @llvm.vector.reduce.add.v8i16(<8 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 {
+ // FIXME MIR inlining messes up LLVM optimizations.
+ // WOULD-CHECK: zext <8 x i8>
+ // WOULD-CHECK-SAME: to <8 x i16>
+ // WOULD-CHECK: call i16 @llvm.vector.reduce.add.v8i16(<8 x i16>
+ x.to_array().into_iter().map(u16::from).sum()
+}
diff --git a/tests/codegen/simd_arith_offset.rs b/tests/codegen/simd_arith_offset.rs
new file mode 100644
index 000000000..7b623a22a
--- /dev/null
+++ b/tests/codegen/simd_arith_offset.rs
@@ -0,0 +1,26 @@
+// compile-flags: -C no-prepopulate-passes
+// only-64bit (because the LLVM type of i64 for usize shows up)
+//
+
+#![crate_type = "lib"]
+#![feature(repr_simd, platform_intrinsics)]
+
+extern "platform-intrinsic" {
+ pub(crate) fn simd_arith_offset<T, U>(ptrs: T, offsets: U) -> T;
+}
+
+/// A vector of *const T.
+#[derive(Debug, Copy, Clone)]
+#[repr(simd)]
+pub struct SimdConstPtr<T, const LANES: usize>([*const T; LANES]);
+
+#[derive(Debug, Copy, Clone)]
+#[repr(simd)]
+pub struct Simd<T, const LANES: usize>([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 {{i8\*|ptr}}> %_3, <8 x i64> %_4
+ unsafe { simd_arith_offset(ptrs, offsets) }
+}
diff --git a/tests/codegen/slice-as_chunks.rs b/tests/codegen/slice-as_chunks.rs
new file mode 100644
index 000000000..48e3f73fc
--- /dev/null
+++ b/tests/codegen/slice-as_chunks.rs
@@ -0,0 +1,33 @@
+// no-system-llvm
+// compile-flags: -O
+// only-64bit (because the LLVM type of i64 for usize shows up)
+// ignore-debug: the debug assertions get in the way
+
+#![crate_type = "lib"]
+#![feature(slice_as_chunks)]
+
+// 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: and i64 %x.1, -4
+ // CHECK: and i64 %x.1, 3
+ // CHECK: lshr exact
+ // CHECK-NOT: mul
+ // CHECK-NOT: udiv
+ // CHECK-NOT: urem
+ // CHECK: ret
+ x.as_chunks()
+}
diff --git a/tests/codegen/slice-init.rs b/tests/codegen/slice-init.rs
new file mode 100644
index 000000000..794b773a7
--- /dev/null
+++ b/tests/codegen/slice-init.rs
@@ -0,0 +1,64 @@
+// 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];
+ drop(&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];
+ drop(&x);
+}
+
+// CHECK-LABEL: @byte_array
+#[no_mangle]
+pub fn byte_array() {
+ // CHECK: call void @llvm.memset.{{.+}}({{i8\*|ptr}} {{.*}}, i8 7, i{{[0-9]+}} 4
+ // CHECK-NOT: br label %repeat_loop_header{{.*}}
+ let x = [7u8; 4];
+ drop(&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.{{.+}}({{i8\*|ptr}} {{.*}}, i8 {{.*}}, i{{[0-9]+}} 4
+ // CHECK-NOT: br label %repeat_loop_header{{.*}}
+ let x = [Init::Memset; 4];
+ drop(&x);
+}
+
+// CHECK-LABEL: @zeroed_integer_array
+#[no_mangle]
+pub fn zeroed_integer_array() {
+ // CHECK: call void @llvm.memset.{{.+}}({{i8\*|ptr}} {{.*}}, i8 0, i{{[0-9]+}} 16
+ // CHECK-NOT: br label %repeat_loop_header{{.*}}
+ let x = [0u32; 4];
+ drop(&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];
+ drop(&x);
+}
diff --git a/tests/codegen/slice-iter-len-eq-zero.rs b/tests/codegen/slice-iter-len-eq-zero.rs
new file mode 100644
index 000000000..894b0ec3d
--- /dev/null
+++ b/tests/codegen/slice-iter-len-eq-zero.rs
@@ -0,0 +1,28 @@
+// no-system-llvm
+// compile-flags: -O
+// ignore-debug: the debug assertions add extra comparisons
+#![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: %2 = icmp eq {{i8\*|ptr}} {{%1|%0}}, {{%1|%0}}
+ // CHECK: ret i1 %2
+ 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: %1 = icmp eq {{i16|i32|i64}}
+ // CHECK: ret i1 %1
+ y.len() == 0
+}
diff --git a/tests/codegen/slice-position-bounds-check.rs b/tests/codegen/slice-position-bounds-check.rs
new file mode 100644
index 000000000..b494f42b2
--- /dev/null
+++ b/tests/codegen/slice-position-bounds-check.rs
@@ -0,0 +1,32 @@
+// no-system-llvm
+// compile-flags: -O -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/slice-ref-equality.rs b/tests/codegen/slice-ref-equality.rs
new file mode 100644
index 000000000..47fde12bf
--- /dev/null
+++ b/tests/codegen/slice-ref-equality.rs
@@ -0,0 +1,38 @@
+// compile-flags: -C opt-level=3 -Zmerge-functions=disabled
+
+#![crate_type = "lib"]
+
+// #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, {{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, {{i32\*|ptr}} %{{.+}}, align 1
+ // CHECK-NEXT: %[[EQ:.+]] = icmp eq i32 %[[LOAD]], 0
+ // CHECK-NEXT: ret i1 %[[EQ]]
+ *data == [0; 4]
+}
diff --git a/tests/codegen/slice-reverse.rs b/tests/codegen/slice-reverse.rs
new file mode 100644
index 000000000..e50b22f3a
--- /dev/null
+++ b/tests/codegen/slice-reverse.rs
@@ -0,0 +1,27 @@
+// compile-flags: -O
+// only-x86_64
+// ignore-debug: the debug assertions in from_raw_parts get in the way
+
+#![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/slice-windows-no-bounds-check.rs b/tests/codegen/slice-windows-no-bounds-check.rs
new file mode 100644
index 000000000..4f5f4425c
--- /dev/null
+++ b/tests/codegen/slice-windows-no-bounds-check.rs
@@ -0,0 +1,35 @@
+#![crate_type = "lib"]
+
+// compile-flags: -O
+
+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/slice_as_from_ptr_range.rs b/tests/codegen/slice_as_from_ptr_range.rs
new file mode 100644
index 000000000..0e3fefd97
--- /dev/null
+++ b/tests/codegen/slice_as_from_ptr_range.rs
@@ -0,0 +1,23 @@
+// compile-flags: -O
+// only-64bit (because we're using [ui]size)
+// ignore-debug (because the assertions get in the way)
+// min-llvm-version: 15.0 (because this is a relatively new instcombine)
+
+#![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/some-abis-do-extend-params-to-32-bits.rs b/tests/codegen/some-abis-do-extend-params-to-32-bits.rs
new file mode 100644
index 000000000..9f2d9d065
--- /dev/null
+++ b/tests/codegen/some-abis-do-extend-params-to-32-bits.rs
@@ -0,0 +1,204 @@
+// 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]
+
+#[lang="sized"] trait Sized { }
+#[lang="freeze"] trait Freeze { }
+#[lang="copy"] trait Copy { }
+
+// 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/some-global-nonnull.rs b/tests/codegen/some-global-nonnull.rs
new file mode 100644
index 000000000..59c47de41
--- /dev/null
+++ b/tests/codegen/some-global-nonnull.rs
@@ -0,0 +1,25 @@
+// compile-flags: -O
+
+#![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/sparc-struct-abi.rs b/tests/codegen/sparc-struct-abi.rs
new file mode 100644
index 000000000..e8816e4f3
--- /dev/null
+++ b/tests/codegen/sparc-struct-abi.rs
@@ -0,0 +1,103 @@
+// Checks that we correctly codegen extern "C" functions returning structs.
+// See issues #52638 and #86163.
+
+// compile-flags: -O --target=sparc64-unknown-linux-gnu --crate-type=rlib
+// needs-llvm-components: sparc
+#![feature(no_core, lang_items)]
+#![no_core]
+
+#[lang="sized"]
+trait Sized { }
+#[lang="freeze"]
+trait Freeze { }
+#[lang="copy"]
+trait Copy { }
+
+#[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/src-hash-algorithm/src-hash-algorithm-md5.rs b/tests/codegen/src-hash-algorithm/src-hash-algorithm-md5.rs
new file mode 100644
index 000000000..64be11277
--- /dev/null
+++ b/tests/codegen/src-hash-algorithm/src-hash-algorithm-md5.rs
@@ -0,0 +1,6 @@
+// compile-flags: -g -Z src-hash-algorithm=md5
+
+#![crate_type = "lib"]
+
+pub fn test() {}
+// CHECK: checksumkind: CSK_MD5
diff --git a/tests/codegen/src-hash-algorithm/src-hash-algorithm-sha1.rs b/tests/codegen/src-hash-algorithm/src-hash-algorithm-sha1.rs
new file mode 100644
index 000000000..54e071521
--- /dev/null
+++ b/tests/codegen/src-hash-algorithm/src-hash-algorithm-sha1.rs
@@ -0,0 +1,6 @@
+// compile-flags: -g -Z src-hash-algorithm=sha1
+
+#![crate_type = "lib"]
+
+pub fn test() {}
+// CHECK: checksumkind: CSK_SHA1
diff --git a/tests/codegen/src-hash-algorithm/src-hash-algorithm-sha256.rs b/tests/codegen/src-hash-algorithm/src-hash-algorithm-sha256.rs
new file mode 100644
index 000000000..dc7db8e23
--- /dev/null
+++ b/tests/codegen/src-hash-algorithm/src-hash-algorithm-sha256.rs
@@ -0,0 +1,6 @@
+// compile-flags: -g -Z src-hash-algorithm=sha256
+
+#![crate_type = "lib"]
+
+pub fn test() {}
+// CHECK: checksumkind: CSK_SHA256
diff --git a/tests/codegen/sse42-implies-crc32.rs b/tests/codegen/sse42-implies-crc32.rs
new file mode 100644
index 000000000..47b1a8993
--- /dev/null
+++ b/tests/codegen/sse42-implies-crc32.rs
@@ -0,0 +1,16 @@
+// only-x86_64
+// min-llvm-version: 14.0
+// 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/stack-probes-call.rs b/tests/codegen/stack-probes-call.rs
new file mode 100644
index 000000000..a18fd41c2
--- /dev/null
+++ b/tests/codegen/stack-probes-call.rs
@@ -0,0 +1,24 @@
+// Check the "probe-stack" attribute for targets with `StackProbeType::Call`,
+// or `StackProbeType::InlineOrCall` when running on older LLVM.
+
+// compile-flags: -C no-prepopulate-passes
+// revisions: i686 x86_64
+//[i686] compile-flags: --target i686-unknown-linux-gnu
+//[i686] needs-llvm-components: x86
+//[i686] ignore-llvm-version: 16 - 99
+//[x86_64] compile-flags: --target x86_64-unknown-linux-gnu
+//[x86_64] needs-llvm-components: x86
+//[x86_64] ignore-llvm-version: 16 - 99
+
+#![crate_type = "rlib"]
+#![feature(no_core, lang_items)]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+
+#[no_mangle]
+pub fn foo() {
+// CHECK: @foo() unnamed_addr #0
+// CHECK: attributes #0 = { {{.*}}"probe-stack"="__rust_probestack"{{.*}} }
+}
diff --git a/tests/codegen/stack-probes-inline.rs b/tests/codegen/stack-probes-inline.rs
new file mode 100644
index 000000000..a6b781de5
--- /dev/null
+++ b/tests/codegen/stack-probes-inline.rs
@@ -0,0 +1,32 @@
+// Check the "probe-stack" attribute for targets with `StackProbeType::Inline`,
+// or `StackProbeType::InlineOrCall` when running on newer LLVM.
+
+// compile-flags: -C no-prepopulate-passes
+// revisions: powerpc powerpc64 powerpc64le s390x i686 x86_64
+//[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
+//[i686] min-llvm-version: 16
+//[x86_64] compile-flags: --target x86_64-unknown-linux-gnu
+//[x86_64] needs-llvm-components: x86
+//[x86_64] min-llvm-version: 16
+
+#![crate_type = "rlib"]
+#![feature(no_core, lang_items)]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+
+#[no_mangle]
+pub fn foo() {
+// CHECK: @foo() unnamed_addr #0
+// CHECK: attributes #0 = { {{.*}}"probe-stack"="inline-asm"{{.*}} }
+}
diff --git a/tests/codegen/stack-protector.rs b/tests/codegen/stack-protector.rs
new file mode 100644
index 000000000..a24e6f1e4
--- /dev/null
+++ b/tests/codegen/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/static-relocation-model-msvc.rs b/tests/codegen/static-relocation-model-msvc.rs
new file mode 100644
index 000000000..735ef7081
--- /dev/null
+++ b/tests/codegen/static-relocation-model-msvc.rs
@@ -0,0 +1,26 @@
+// Verify linkage of external symbols in the static relocation model on MSVC.
+//
+// compile-flags: -O -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/staticlib-external-inline-fns.rs b/tests/codegen/staticlib-external-inline-fns.rs
new file mode 100644
index 000000000..432c063e8
--- /dev/null
+++ b/tests/codegen/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/stores.rs b/tests/codegen/stores.rs
new file mode 100644
index 000000000..837256e53
--- /dev/null
+++ b/tests/codegen/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 i32
+// CHECK: %y = alloca [4 x i8]
+// CHECK: store i32 %0, {{i32\*|ptr}} [[TMP]]
+// CHECK: call void @llvm.memcpy.{{.*}}({{i8\*|ptr}} align 1 {{.+}}, {{i8\*|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 i32
+// CHECK: %y = alloca %Bytes
+// CHECK: store i32 %0, {{i32\*|ptr}} [[TMP]]
+// CHECK: call void @llvm.memcpy.{{.*}}({{i8\*|ptr}} align 1 {{.+}}, {{i8\*|ptr}} align 4 {{.+}}, i{{[0-9]+}} 4, i1 false)
+ *x = y;
+}
diff --git a/tests/codegen/swap-large-types.rs b/tests/codegen/swap-large-types.rs
new file mode 100644
index 000000000..4a6840357
--- /dev/null
+++ b/tests/codegen/swap-large-types.rs
@@ -0,0 +1,91 @@
+// compile-flags: -O
+// only-x86_64
+// ignore-debug: the debug assertions get in the way
+
+#![crate_type = "lib"]
+
+use std::mem::swap;
+use std::ptr::{read, copy_nonoverlapping, 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.
+
+// CHECK-LABEL: @swap_basic
+#[no_mangle]
+pub fn swap_basic(x: &mut KeccakBuffer, y: &mut KeccakBuffer) {
+// CHECK: alloca [5 x [5 x i64]]
+
+ // 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);
+ }
+}
+
+// This test verifies that the library does something smarter, and thus
+// doesn't need any scratch space on the stack.
+
+// CHECK-LABEL: @swap_std
+#[no_mangle]
+pub fn swap_std(x: &mut KeccakBuffer, y: &mut KeccakBuffer) {
+// CHECK-NOT: alloca
+// CHECK: load <{{[0-9]+}} x i64>
+// CHECK: store <{{[0-9]+}} x i64>
+ swap(x, y)
+}
+
+// Verify that types with usize alignment are swapped via vectored usizes,
+// not falling back to byte-level code.
+
+// CHECK-LABEL: @swap_slice
+#[no_mangle]
+pub fn swap_slice(x: &mut [KeccakBuffer], y: &mut [KeccakBuffer]) {
+// CHECK-NOT: alloca
+// CHECK: load <{{[0-9]+}} x i64>
+// CHECK: store <{{[0-9]+}} x i64>
+ if x.len() == y.len() {
+ x.swap_with_slice(y);
+ }
+}
+
+// But for a large align-1 type, vectorized byte copying is what we want.
+
+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: load <{{[0-9]+}} x i8>
+// CHECK: store <{{[0-9]+}} x i8>
+ if x.len() == y.len() {
+ x.swap_with_slice(y);
+ }
+}
+
+// This verifies that the 2×read + 2×write optimizes to just 3 memcpys
+// for an unusual type like this. It's not clear whether we should do anything
+// smarter in Rust for these, so for now it's fine to leave these up to the backend.
+// That's not as bad as it might seem, as for example, LLVM will lower the
+// memcpys below to VMOVAPS on YMMs if one enables the AVX target feature.
+// Eventually we'll be able to pass `align_of::<T>` to a const generic and
+// thus pick a smarter chunk size ourselves without huge code duplication.
+
+#[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: call void @llvm.memcpy.{{.+}}({{i8\*|ptr}} noundef nonnull align 64 dereferenceable(192)
+// CHECK: call void @llvm.memcpy.{{.+}}({{i8\*|ptr}} noundef nonnull align 64 dereferenceable(192)
+// CHECK: call void @llvm.memcpy.{{.+}}({{i8\*|ptr}} noundef nonnull align 64 dereferenceable(192)
+// CHECK-NOT: call void @llvm.memcpy
+ swap(x, y)
+}
diff --git a/tests/codegen/swap-simd-types.rs b/tests/codegen/swap-simd-types.rs
new file mode 100644
index 000000000..c90b277eb
--- /dev/null
+++ b/tests/codegen/swap-simd-types.rs
@@ -0,0 +1,32 @@
+// compile-flags: -O -C target-feature=+avx
+// only-x86_64
+// ignore-debug: the debug assertions get in the way
+
+#![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: load <8 x float>{{.+}}align 32
+// CHECK: store <8 x float>{{.+}}align 32
+ if x.len() == y.len() {
+ x.swap_with_slice(y);
+ }
+}
diff --git a/tests/codegen/swap-small-types.rs b/tests/codegen/swap-small-types.rs
new file mode 100644
index 000000000..03e2a2327
--- /dev/null
+++ b/tests/codegen/swap-small-types.rs
@@ -0,0 +1,63 @@
+// compile-flags: -O
+// only-x86_64
+// ignore-debug: the debug assertions get in the way
+
+#![crate_type = "lib"]
+
+use std::mem::swap;
+
+type RGB48 = [u16; 3];
+
+// CHECK-LABEL: @swap_rgb48
+#[no_mangle]
+pub fn swap_rgb48(x: &mut RGB48, y: &mut RGB48) {
+ // FIXME MIR inlining messes up LLVM optimizations.
+// WOULD-CHECK-NOT: alloca
+// WOULD-CHECK: load i48
+// WOULD-CHECK: store i48
+ swap(x, y)
+}
+
+// LLVM doesn't vectorize a loop over 3-byte elements,
+// so we chunk it down to bytes and loop over those instead.
+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: load <{{[0-9]+}} x i8>
+// CHECK: store <{{[0-9]+}} x i8>
+ if x.len() == y.len() {
+ x.swap_with_slice(y);
+ }
+}
+
+// This one has a power-of-two size, so we iterate over it directly
+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
+// CHECK: load <{{[0-9]+}} x i32>
+// CHECK: store <{{[0-9]+}} x i32>
+ 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>
+// CHECK: store <{{[0-9]+}} x i64>
+ if x.len() == y.len() {
+ x.swap_with_slice(y);
+ }
+}
diff --git a/tests/codegen/target-cpu-on-functions.rs b/tests/codegen/target-cpu-on-functions.rs
new file mode 100644
index 000000000..c043eceb5
--- /dev/null
+++ b/tests/codegen/target-cpu-on-functions.rs
@@ -0,0 +1,21 @@
+// 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 {{.*}}() {{.*}} #0
+fn not_exported() {}
+
+// CHECK: attributes #0 = {{.*}} "target-cpu"="{{.*}}"
diff --git a/tests/codegen/target-feature-overrides.rs b/tests/codegen/target-feature-overrides.rs
new file mode 100644
index 000000000..1bebf66f0
--- /dev/null
+++ b/tests/codegen/target-feature-overrides.rs
@@ -0,0 +1,47 @@
+// revisions: COMPAT INCOMPAT
+// needs-llvm-components: x86
+// compile-flags: --target=x86_64-unknown-linux-gnu -Copt-level=3
+// [COMPAT] compile-flags: -Ctarget-feature=+avx2,+avx
+// [INCOMPAT] compile-flags: -Ctarget-feature=-avx2,-avx
+
+// See also tests/assembly/target-feature-multiple.rs
+#![feature(no_core, lang_items)]
+#![crate_type = "lib"]
+#![no_core]
+
+
+#[lang = "sized"]
+trait Sized {}
+#[lang = "copy"]
+trait Copy {}
+
+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"="+avx2,+avx,+avx"
+// INCOMPAT-SAME: "target-features"="-avx2,-avx,+avx"
+// CHECK: attributes [[BANANAATTRS]]
+// COMPAT-SAME: "target-features"="+avx2,+avx"
+// INCOMPAT-SAME: "target-features"="-avx2,-avx"
diff --git a/tests/codegen/thread-local.rs b/tests/codegen/thread-local.rs
new file mode 100644
index 000000000..0f1b29ca7
--- /dev/null
+++ b/tests/codegen/thread-local.rs
@@ -0,0 +1,49 @@
+// compile-flags: -O
+// aux-build:thread_local_aux.rs
+// ignore-windows FIXME(#84933)
+// 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]
+
+#![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 local_unnamed_addr global i64
+// CHECK: [[TLS:@.+]] = internal thread_local unnamed_addr global
+
+// CHECK-LABEL: @get
+#[no_mangle]
+fn get() -> u32 {
+ // CHECK: %0 = load i32, {{.*}}[[TLS]]{{.*}}
+ // CHECK-NEXT: ret i32 %0
+ A.with(|a| a.get())
+}
+
+// CHECK-LABEL: @set
+#[no_mangle]
+fn set(v: u32) {
+ // CHECK: store i32 %0, {{.*}}[[TLS]]{{.*}}
+ // CHECK-NEXT: ret void
+ A.with(|a| a.set(v))
+}
+
+// CHECK-LABEL: @get_aux
+#[no_mangle]
+fn get_aux() -> u64 {
+ // CHECK: %0 = load i64, {{.*}}[[TLS_AUX]]
+ // CHECK-NEXT: ret i64 %0
+ aux::A.with(|a| a.get())
+}
+
+// CHECK-LABEL: @set_aux
+#[no_mangle]
+fn set_aux(v: u64) {
+ // CHECK: store i64 %0, {{.*}}[[TLS_AUX]]
+ // CHECK-NEXT: ret void
+ aux::A.with(|a| a.set(v))
+}
diff --git a/tests/codegen/to_vec.rs b/tests/codegen/to_vec.rs
new file mode 100644
index 000000000..60dc4efcb
--- /dev/null
+++ b/tests/codegen/to_vec.rs
@@ -0,0 +1,10 @@
+// compile-flags: -O
+
+#![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/transmute-scalar.rs b/tests/codegen/transmute-scalar.rs
new file mode 100644
index 000000000..260dcbac0
--- /dev/null
+++ b/tests/codegen/transmute-scalar.rs
@@ -0,0 +1,81 @@
+// compile-flags: -O -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+// FIXME(eddyb) all of these tests show memory stores and loads, even after a
+// scalar `bitcast`, more special-casing is required to remove `alloca` usage.
+
+// CHECK-LABEL: define{{.*}}i32 @f32_to_bits(float noundef %x)
+// CHECK: store i32 %{{.*}}, {{.*}} %0
+// CHECK-NEXT: %[[RES:.*]] = load i32, {{.*}} %0
+// CHECK: ret i32 %[[RES]]
+#[no_mangle]
+pub fn f32_to_bits(x: f32) -> u32 {
+ unsafe { std::mem::transmute(x) }
+}
+
+// CHECK-LABEL: define{{.*}}i8 @bool_to_byte(i1 noundef zeroext %b)
+// CHECK: %1 = zext i1 %b to i8
+// CHECK-NEXT: store i8 %1, {{.*}} %0
+// CHECK-NEXT: %2 = load i8, {{.*}} %0
+// CHECK: ret i8 %2
+#[no_mangle]
+pub fn bool_to_byte(b: bool) -> u8 {
+ unsafe { std::mem::transmute(b) }
+}
+
+// CHECK-LABEL: define{{.*}}noundef zeroext i1 @byte_to_bool(i8 noundef %byte)
+// CHECK: %1 = trunc i8 %byte to i1
+// CHECK-NEXT: %2 = zext i1 %1 to i8
+// CHECK-NEXT: store i8 %2, {{.*}} %0
+// CHECK-NEXT: %3 = load i8, {{.*}} %0
+// CHECK-NEXT: %4 = trunc i8 %3 to i1
+// CHECK: ret i1 %4
+#[no_mangle]
+pub unsafe fn byte_to_bool(byte: u8) -> bool {
+ std::mem::transmute(byte)
+}
+
+// CHECK-LABEL: define{{.*}}{{i8\*|ptr}} @ptr_to_ptr({{i16\*|ptr}} noundef %p)
+// CHECK: store {{i8\*|ptr}} %{{.*}}, {{.*}} %0
+// CHECK-NEXT: %[[RES:.*]] = load {{i8\*|ptr}}, {{.*}} %0
+// CHECK: ret {{i8\*|ptr}} %[[RES]]
+#[no_mangle]
+pub fn ptr_to_ptr(p: *mut u16) -> *mut u8 {
+ unsafe { std::mem::transmute(p) }
+}
+
+// HACK(eddyb) scalar `transmute`s between pointers and non-pointers are
+// currently not special-cased like other scalar `transmute`s, because
+// LLVM requires specifically `ptrtoint`/`inttoptr` instead of `bitcast`.
+//
+// Tests below show the non-special-cased behavior (with the possible
+// future special-cased instructions in the "NOTE(eddyb)" comments).
+
+// CHECK: define{{.*}}[[USIZE:i[0-9]+]] @ptr_to_int({{i16\*|ptr}} noundef %p)
+
+// NOTE(eddyb) see above, the following two CHECK lines should ideally be this:
+// %2 = ptrtoint i16* %p to [[USIZE]]
+// store [[USIZE]] %2, [[USIZE]]* %0
+// CHECK: store {{i16\*|ptr}} %p, {{.*}}
+
+// CHECK-NEXT: %[[RES:.*]] = load [[USIZE]], {{.*}} %0
+// CHECK: ret [[USIZE]] %[[RES]]
+#[no_mangle]
+pub fn ptr_to_int(p: *mut u16) -> usize {
+ unsafe { std::mem::transmute(p) }
+}
+
+// CHECK: define{{.*}}{{i16\*|ptr}} @int_to_ptr([[USIZE]] noundef %i)
+
+// NOTE(eddyb) see above, the following two CHECK lines should ideally be this:
+// %2 = inttoptr [[USIZE]] %i to i16*
+// store i16* %2, i16** %0
+// CHECK: store [[USIZE]] %i, {{.*}}
+
+// CHECK-NEXT: %[[RES:.*]] = load {{i16\*|ptr}}, {{.*}} %0
+// CHECK: ret {{i16\*|ptr}} %[[RES]]
+#[no_mangle]
+pub fn int_to_ptr(i: usize) -> *mut u16 {
+ unsafe { std::mem::transmute(i) }
+}
diff --git a/tests/codegen/try_identity.rs b/tests/codegen/try_identity.rs
new file mode 100644
index 000000000..92be90014
--- /dev/null
+++ b/tests/codegen/try_identity.rs
@@ -0,0 +1,34 @@
+// compile-flags: -C no-prepopulate-passes -O -Z mir-opt-level=3 -Zunsound-mir-opts
+
+// Ensure that `x?` has no overhead on `Result<T, E>` due to identity `match`es in lowering.
+// This requires inlining to trigger the MIR optimizations in `SimplifyArmIdentity`.
+
+#![crate_type = "lib"]
+
+type R = Result<u64, i32>;
+
+// This was written to the `?` from `try_trait`, but `try_trait_v2` uses a different structure,
+// so the relevant desugar is copied inline in order to keep the test testing the same thing.
+// FIXME(#85133): while this might be useful for `r#try!`, it would be nice to have a MIR
+// optimization that picks up the `?` desugaring, as `SimplifyArmIdentity` does not.
+#[no_mangle]
+pub fn try_identity(x: R) -> R {
+// CHECK: start:
+// FIXME(JakobDegen): Broken by deaggregation change CHECK-NOT\: br {{.*}}
+// CHECK ret void
+ let y = match into_result(x) {
+ Err(e) => return from_error(From::from(e)),
+ Ok(v) => v,
+ };
+ Ok(y)
+}
+
+#[inline]
+fn into_result<T, E>(r: Result<T, E>) -> Result<T, E> {
+ r
+}
+
+#[inline]
+fn from_error<T, E>(e: E) -> Result<T, E> {
+ Err(e)
+}
diff --git a/tests/codegen/try_question_mark_nop.rs b/tests/codegen/try_question_mark_nop.rs
new file mode 100644
index 000000000..d23938776
--- /dev/null
+++ b/tests/codegen/try_question_mark_nop.rs
@@ -0,0 +1,54 @@
+// min-llvm-version: 15.0
+// compile-flags: -O -Z merge-functions=disabled --edition=2021
+// only-x86_64
+
+#![crate_type = "lib"]
+#![feature(try_blocks)]
+
+// These are now NOPs in LLVM 15, presumably thanks to nikic's change mentioned in
+// <https://github.com/rust-lang/rust/issues/85133#issuecomment-1072168354>.
+// Unfortunately, as of 2022-08-17 they're not yet nops for `u64`s nor `Option`.
+
+use std::ops::ControlFlow::{self, Continue, Break};
+
+// 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: ret i64 %0
+ 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: ret i64 %0
+ 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: ret i64 %0
+ 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: ret i64 %0
+ try {
+ x?
+ }
+}
diff --git a/tests/codegen/tune-cpu-on-functions.rs b/tests/codegen/tune-cpu-on-functions.rs
new file mode 100644
index 000000000..ed8dc0e93
--- /dev/null
+++ b/tests/codegen/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
+
+#![crate_type = "staticlib"]
+
+// CHECK-LABEL: define {{.*}} @exported() {{.*}} #0
+#[no_mangle]
+pub extern 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/tuple-layout-opt.rs b/tests/codegen/tuple-layout-opt.rs
new file mode 100644
index 000000000..35f760851
--- /dev/null
+++ b/tests/codegen/tuple-layout-opt.rs
@@ -0,0 +1,36 @@
+// ignore-emscripten
+// 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, ());
+// CHECK: define i128 @test_ScalarZstLast(i128 %_1)
+#[no_mangle]
+pub fn test_ScalarZstLast(_: ScalarZstLast) -> ScalarZstLast { loop {} }
+
+type ScalarZstFirst = ((), u128);
+// CHECK: define i128 @test_ScalarZstFirst(i128 %_1)
+#[no_mangle]
+pub fn test_ScalarZstFirst(_: ScalarZstFirst) -> ScalarZstFirst { loop {} }
+
+type ScalarPairZstLast = (u8, u128, ());
+// CHECK: define { i128, i8 } @test_ScalarPairZstLast(i128 %_1.0, i8 %_1.1)
+#[no_mangle]
+pub fn test_ScalarPairZstLast(_: ScalarPairZstLast) -> ScalarPairZstLast { loop {} }
+
+type ScalarPairZstFirst = ((), u8, u128);
+// CHECK: define { i8, i128 } @test_ScalarPairZstFirst(i8 %_1.0, i128 %_1.1)
+#[no_mangle]
+pub fn test_ScalarPairZstFirst(_: ScalarPairZstFirst) -> ScalarPairZstFirst { loop {} }
+
+type ScalarPairLotsOfZsts = ((), u8, (), u128, ());
+// CHECK: define { i128, i8 } @test_ScalarPairLotsOfZsts(i128 %_1.0, i8 %_1.1)
+#[no_mangle]
+pub fn test_ScalarPairLotsOfZsts(_: ScalarPairLotsOfZsts) -> ScalarPairLotsOfZsts { loop {} }
+
+type ScalarPairLottaNesting = (((), ((), u8, (), u128, ())), ());
+// CHECK: define { i128, i8 } @test_ScalarPairLottaNesting(i128 %_1.0, i8 %_1.1)
+#[no_mangle]
+pub fn test_ScalarPairLottaNesting(_: ScalarPairLottaNesting) -> ScalarPairLottaNesting { loop {} }
diff --git a/tests/codegen/unchecked-float-casts.rs b/tests/codegen/unchecked-float-casts.rs
new file mode 100644
index 000000000..4e3bfcd43
--- /dev/null
+++ b/tests/codegen/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/unchecked_shifts.rs b/tests/codegen/unchecked_shifts.rs
new file mode 100644
index 000000000..60d0cb09a
--- /dev/null
+++ b/tests/codegen/unchecked_shifts.rs
@@ -0,0 +1,66 @@
+// compile-flags: -O
+// min-llvm-version: 15.0 (LLVM 13 in CI does this differently from submodule LLVM)
+// ignore-debug (because unchecked is checked in debug)
+
+#![crate_type = "lib"]
+#![feature(unchecked_math)]
+
+// CHECK-LABEL: @unchecked_shl_unsigned_same
+#[no_mangle]
+pub unsafe fn unchecked_shl_unsigned_same(a: u32, b: u32) -> u32 {
+ // 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 {
+ // This uses -DAG to avoid failing on irrelevant reorderings,
+ // like emitting the truncation earlier.
+
+ // CHECK-DAG: %[[INRANGE:.+]] = icmp ult i32 %b, 65536
+ // CHECK-DAG: tail call void @llvm.assume(i1 %[[INRANGE]])
+ // CHECK-DAG: %[[TRUNC:.+]] = trunc i32 %b to i16
+ // CHECK-DAG: 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: %[[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: 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 {
+ // This uses -DAG to avoid failing on irrelevant reorderings,
+ // like emitting the truncation earlier.
+
+ // CHECK-DAG: %[[INRANGE:.+]] = icmp ult i32 %b, 32768
+ // CHECK-DAG: tail call void @llvm.assume(i1 %[[INRANGE]])
+ // CHECK-DAG: %[[TRUNC:.+]] = trunc i32 %b to i16
+ // CHECK-DAG: 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: %[[EXT:.+]] = zext i32 %b to i64
+ // CHECK: ashr i64 %a, %[[EXT]]
+ a.unchecked_shr(b)
+}
diff --git a/tests/codegen/uninit-consts.rs b/tests/codegen/uninit-consts.rs
new file mode 100644
index 000000000..98a6761f8
--- /dev/null
+++ b/tests/codegen/uninit-consts.rs
@@ -0,0 +1,55 @@
+// compile-flags: -C no-prepopulate-passes
+// min-llvm-version: 14.0
+
+// 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:@[0-9]+]] = private unnamed_addr constant <{ [10 x i8] }> undef
+
+// CHECK: [[PARTIALLY_UNINIT:@[0-9]+]] = 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:@[0-9]+]] = private unnamed_addr constant <{ [32768 x i8] }> <{ [32768 x i8] c"{{.+}}" }>, align 4
+
+// CHECK: [[FULLY_UNINIT_HUGE:@[0-9]+]] = 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.{{.+}}({{i8\*|ptr}} align 1 %{{[0-9]+}}, {{i8\*|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.{{.+}}({{i8\*|ptr}} align 4 %{{[0-9]+}}, {{i8\*|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.{{.+}}({{i8\*|ptr}} align 4 %{{[0-9]+}}, {{i8\*|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.{{.+}}({{i8\*|ptr}} align 4 %{{[0-9]+}}, {{i8\*|ptr}} align 4 {{.*}}[[FULLY_UNINIT_HUGE]]{{.*}}, i{{(32|64)}} 16384, i1 false)
+ F
+}
diff --git a/tests/codegen/union-abi.rs b/tests/codegen/union-abi.rs
new file mode 100644
index 000000000..c18f2a49f
--- /dev/null
+++ b/tests/codegen/union-abi.rs
@@ -0,0 +1,76 @@
+// ignore-emscripten vectors passed directly
+// compile-flags: -O -C no-prepopulate-passes
+
+// 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, i64, i64, i64);
+
+#[derive(Copy, Clone)]
+pub union UnionI64x4{ a:(), b: i64x4 }
+
+// CHECK: define void @test_UnionI64x4({{<4 x i64>\*|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 void @test_UnionI64x4_({{<4 x i64>\*|ptr}} {{.*}} %_1)
+#[no_mangle]
+pub fn test_UnionI64x4_(_: UnionI64x4_) { loop {} }
+
+pub union UnionI64x4I64{ a: i64x4, b: i64 }
+
+// CHECK: define void @test_UnionI64x4I64({{%UnionI64x4I64\*|ptr}} {{.*}} %_1)
+#[no_mangle]
+pub fn test_UnionI64x4I64(_: UnionI64x4I64) { loop {} }
+
+pub union UnionI64x4Tuple{ a: i64x4, b: (i64, i64, i64, i64) }
+
+// CHECK: define void @test_UnionI64x4Tuple({{%UnionI64x4Tuple\*|ptr}} {{.*}} %_1)
+#[no_mangle]
+pub fn test_UnionI64x4Tuple(_: UnionI64x4Tuple) { loop {} }
+
+
+pub union UnionF32{a:f32}
+
+// CHECK: define float @test_UnionF32(float %_1)
+#[no_mangle]
+pub fn test_UnionF32(_: UnionF32) -> UnionF32 { loop {} }
+
+pub union UnionF32F32{a:f32, b:f32}
+
+// CHECK: define float @test_UnionF32F32(float %_1)
+#[no_mangle]
+pub fn test_UnionF32F32(_: UnionF32F32) -> UnionF32F32 { loop {} }
+
+pub union UnionF32U32{a:f32, b:u32}
+
+// CHECK: define i32 @test_UnionF32U32(i32{{( %0)?}})
+#[no_mangle]
+pub fn test_UnionF32U32(_: UnionF32U32) -> UnionF32U32 { loop {} }
+
+pub union UnionU128{a:u128}
+// CHECK: define i128 @test_UnionU128(i128 %_1)
+#[no_mangle]
+pub fn test_UnionU128(_: UnionU128) -> UnionU128 { loop {} }
+
+#[repr(C)]
+pub union CUnionU128{a:u128}
+// CHECK: define void @test_CUnionU128({{%CUnionU128\*|ptr}} {{.*}} %_1)
+#[no_mangle]
+pub fn test_CUnionU128(_: CUnionU128) { loop {} }
+
+pub union UnionBool { b:bool }
+// CHECK: define noundef zeroext i1 @test_UnionBool(i8 %b)
+#[no_mangle]
+pub fn test_UnionBool(b: UnionBool) -> bool { unsafe { b.b } }
+// CHECK: %0 = trunc i8 %b to i1
diff --git a/tests/codegen/unpadded-simd.rs b/tests/codegen/unpadded-simd.rs
new file mode 100644
index 000000000..eb44dbd93
--- /dev/null
+++ b/tests/codegen/unpadded-simd.rs
@@ -0,0 +1,14 @@
+// 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)]
+
+#[derive(Copy, Clone, Debug)]
+#[repr(simd)]
+pub struct int16x4_t(pub i16, pub i16, pub i16, pub i16);
+
+#[derive(Copy, Clone, Debug)]
+pub struct int16x4x2_t(pub int16x4_t, pub int16x4_t);
+// CHECK: %int16x4x2_t = type { <4 x i16>, <4 x i16> }
diff --git a/tests/codegen/unwind-abis/aapcs-unwind-abi.rs b/tests/codegen/unwind-abis/aapcs-unwind-abi.rs
new file mode 100644
index 000000000..c092e28a0
--- /dev/null
+++ b/tests/codegen/unwind-abis/aapcs-unwind-abi.rs
@@ -0,0 +1,31 @@
+// needs-llvm-components: arm
+// compile-flags: --target=armv7-unknown-linux-gnueabihf --crate-type=rlib -Cno-prepopulate-passes
+#![no_core]
+#![feature(no_core, lang_items, c_unwind)]
+#[lang="sized"]
+trait Sized { }
+
+// 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/unwind-abis/c-unwind-abi-panic-abort.rs b/tests/codegen/unwind-abis/c-unwind-abi-panic-abort.rs
new file mode 100644
index 000000000..ea5bae18e
--- /dev/null
+++ b/tests/codegen/unwind-abis/c-unwind-abi-panic-abort.rs
@@ -0,0 +1,28 @@
+// 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"]
+#![feature(c_unwind)]
+
+// 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/unwind-abis/c-unwind-abi.rs b/tests/codegen/unwind-abis/c-unwind-abi.rs
new file mode 100644
index 000000000..e258dbcac
--- /dev/null
+++ b/tests/codegen/unwind-abis/c-unwind-abi.rs
@@ -0,0 +1,29 @@
+// compile-flags: -C opt-level=0
+
+// 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"]
+#![feature(c_unwind)]
+
+// 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/unwind-abis/cdecl-unwind-abi.rs b/tests/codegen/unwind-abis/cdecl-unwind-abi.rs
new file mode 100644
index 000000000..19a722883
--- /dev/null
+++ b/tests/codegen/unwind-abis/cdecl-unwind-abi.rs
@@ -0,0 +1,29 @@
+// compile-flags: -C opt-level=0
+
+// 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"]
+#![feature(c_unwind)]
+
+// 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/unwind-abis/fastcall-unwind-abi.rs b/tests/codegen/unwind-abis/fastcall-unwind-abi.rs
new file mode 100644
index 000000000..b74099a5d
--- /dev/null
+++ b/tests/codegen/unwind-abis/fastcall-unwind-abi.rs
@@ -0,0 +1,31 @@
+// needs-llvm-components: x86
+// compile-flags: --target=i686-pc-windows-msvc --crate-type=rlib -Cno-prepopulate-passes
+#![no_core]
+#![feature(no_core, lang_items, c_unwind)]
+#[lang="sized"]
+trait Sized { }
+
+// 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/unwind-abis/nounwind-on-stable-panic-abort.rs b/tests/codegen/unwind-abis/nounwind-on-stable-panic-abort.rs
new file mode 100644
index 000000000..106d593b2
--- /dev/null
+++ b/tests/codegen/unwind-abis/nounwind-on-stable-panic-abort.rs
@@ -0,0 +1,16 @@
+// compile-flags: -C opt-level=0 -Cpanic=abort
+// ignore-wasm32-bare compiled with panic=abort by default
+
+#![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/unwind-abis/nounwind-on-stable-panic-unwind.rs b/tests/codegen/unwind-abis/nounwind-on-stable-panic-unwind.rs
new file mode 100644
index 000000000..c1c5bbdda
--- /dev/null
+++ b/tests/codegen/unwind-abis/nounwind-on-stable-panic-unwind.rs
@@ -0,0 +1,17 @@
+// compile-flags: -C opt-level=0
+// ignore-wasm32-bare compiled with panic=abort by default
+
+#![crate_type = "lib"]
+
+// We disable optimizations to prevent LLVM from inferring the attribute.
+
+extern "C" {
+ fn bar();
+}
+
+// CHECK-NOT: Function Attrs:{{.*}}nounwind
+pub unsafe extern "C" fn foo() {
+ bar();
+}
+
+// Note that this test will get removed when `C-unwind` is fully stabilized
diff --git a/tests/codegen/unwind-abis/nounwind.rs b/tests/codegen/unwind-abis/nounwind.rs
new file mode 100644
index 000000000..c46d71733
--- /dev/null
+++ b/tests/codegen/unwind-abis/nounwind.rs
@@ -0,0 +1,17 @@
+// compile-flags: -C opt-level=0 -Cpanic=abort
+// ignore-wasm32-bare compiled with panic=abort by default
+
+#![crate_type = "lib"]
+#![feature(c_unwind)]
+
+// 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/unwind-abis/stdcall-unwind-abi.rs b/tests/codegen/unwind-abis/stdcall-unwind-abi.rs
new file mode 100644
index 000000000..8eff0719f
--- /dev/null
+++ b/tests/codegen/unwind-abis/stdcall-unwind-abi.rs
@@ -0,0 +1,31 @@
+// needs-llvm-components: x86
+// compile-flags: --target=i686-pc-windows-msvc --crate-type=rlib -Cno-prepopulate-passes
+#![no_core]
+#![feature(no_core, lang_items, c_unwind)]
+#[lang="sized"]
+trait Sized { }
+
+// 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/unwind-abis/system-unwind-abi.rs b/tests/codegen/unwind-abis/system-unwind-abi.rs
new file mode 100644
index 000000000..2591c1d48
--- /dev/null
+++ b/tests/codegen/unwind-abis/system-unwind-abi.rs
@@ -0,0 +1,29 @@
+// compile-flags: -C opt-level=0
+
+// 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"]
+#![feature(c_unwind)]
+
+// 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/unwind-abis/sysv64-unwind-abi.rs b/tests/codegen/unwind-abis/sysv64-unwind-abi.rs
new file mode 100644
index 000000000..694fde17c
--- /dev/null
+++ b/tests/codegen/unwind-abis/sysv64-unwind-abi.rs
@@ -0,0 +1,31 @@
+// 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, c_unwind)]
+#[lang="sized"]
+trait Sized { }
+
+// 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/unwind-abis/thiscall-unwind-abi.rs b/tests/codegen/unwind-abis/thiscall-unwind-abi.rs
new file mode 100644
index 000000000..7e81367fc
--- /dev/null
+++ b/tests/codegen/unwind-abis/thiscall-unwind-abi.rs
@@ -0,0 +1,31 @@
+// needs-llvm-components: x86
+// compile-flags: --target=i686-pc-windows-msvc --crate-type=rlib -Cno-prepopulate-passes
+#![no_core]
+#![feature(no_core, lang_items, c_unwind, abi_thiscall)]
+#[lang="sized"]
+trait Sized { }
+
+// 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/unwind-abis/vectorcall-unwind-abi.rs b/tests/codegen/unwind-abis/vectorcall-unwind-abi.rs
new file mode 100644
index 000000000..d7eca2a97
--- /dev/null
+++ b/tests/codegen/unwind-abis/vectorcall-unwind-abi.rs
@@ -0,0 +1,31 @@
+// needs-llvm-components: x86
+// compile-flags: --target=i686-pc-windows-msvc --crate-type=rlib -Cno-prepopulate-passes
+#![no_core]
+#![feature(no_core, lang_items, c_unwind, abi_vectorcall)]
+#[lang="sized"]
+trait Sized { }
+
+// 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/unwind-abis/win64-unwind-abi.rs b/tests/codegen/unwind-abis/win64-unwind-abi.rs
new file mode 100644
index 000000000..6591348c3
--- /dev/null
+++ b/tests/codegen/unwind-abis/win64-unwind-abi.rs
@@ -0,0 +1,31 @@
+// 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, c_unwind)]
+#[lang="sized"]
+trait Sized { }
+
+// 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/unwind-and-panic-abort.rs b/tests/codegen/unwind-and-panic-abort.rs
new file mode 100644
index 000000000..e43e73b96
--- /dev/null
+++ b/tests/codegen/unwind-and-panic-abort.rs
@@ -0,0 +1,17 @@
+// compile-flags: -C panic=abort
+
+#![crate_type = "lib"]
+#![feature(c_unwind)]
+
+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/unwind-extern-exports.rs b/tests/codegen/unwind-extern-exports.rs
new file mode 100644
index 000000000..6ac3c079f
--- /dev/null
+++ b/tests/codegen/unwind-extern-exports.rs
@@ -0,0 +1,16 @@
+// compile-flags: -C opt-level=0
+// ignore-wasm32-bare compiled with panic=abort by default
+
+#![crate_type = "lib"]
+#![feature(c_unwind)]
+
+// 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/unwind-extern-imports.rs b/tests/codegen/unwind-extern-imports.rs
new file mode 100644
index 000000000..e33e3e805
--- /dev/null
+++ b/tests/codegen/unwind-extern-imports.rs
@@ -0,0 +1,22 @@
+// compile-flags: -C no-prepopulate-passes
+// ignore-wasm32-bare compiled with panic=abort by default
+
+#![crate_type = "lib"]
+#![feature(c_unwind)]
+
+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/used_with_arg.rs b/tests/codegen/used_with_arg.rs
new file mode 100644
index 000000000..4515cb2ae
--- /dev/null
+++ b/tests/codegen/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/var-names.rs b/tests/codegen/var-names.rs
new file mode 100644
index 000000000..d4715efad
--- /dev/null
+++ b/tests/codegen/var-names.rs
@@ -0,0 +1,15 @@
+// compile-flags: -O -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: define{{.*}}i32 @test(i32 noundef %a, i32 noundef %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/vec-calloc-llvm14.rs b/tests/codegen/vec-calloc-llvm14.rs
new file mode 100644
index 000000000..08302796c
--- /dev/null
+++ b/tests/codegen/vec-calloc-llvm14.rs
@@ -0,0 +1,144 @@
+// compile-flags: -O
+// only-x86_64
+// ignore-debug
+
+#![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]
+}
diff --git a/tests/codegen/vec-calloc.rs b/tests/codegen/vec-calloc.rs
new file mode 100644
index 000000000..4481a9d1e
--- /dev/null
+++ b/tests/codegen/vec-calloc.rs
@@ -0,0 +1,184 @@
+// compile-flags: -O -Z merge-functions=disabled
+// only-x86_64
+// ignore-debug
+// min-llvm-version: 15.0
+
+#![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/vec-in-place.rs b/tests/codegen/vec-in-place.rs
new file mode 100644
index 000000000..5df366905
--- /dev/null
+++ b/tests/codegen/vec-in-place.rs
@@ -0,0 +1,74 @@
+// min-llvm-version: 14.0
+// ignore-debug: the debug assertions get in the way
+// compile-flags: -O -Z merge-functions=disabled
+#![crate_type = "lib"]
+
+// Ensure that trivial casts of vec elements are O(1)
+
+pub struct Wrapper<T>(T);
+
+#[repr(C)]
+pub struct Foo {
+ a: u64,
+ b: u64,
+ c: u64,
+ d: u64,
+}
+
+// Going from an aggregate struct to another type currently requires Copy to
+// enable the TrustedRandomAccess specialization. Without it optimizations do not yet
+// reliably recognize the loops as noop for repr(C) or non-Copy structs.
+#[derive(Copy, Clone)]
+pub struct Bar {
+ 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
+ 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
+ vec.into_iter().map(|e| Wrapper(e)).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
+ 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> {
+ // FIXME These checks should be the same as other functions.
+ // CHECK-NOT: @__rust_alloc
+ // CHECK-NOT: @__rust_alloc
+ vec.into_iter().map(|e| unsafe { std::mem::transmute(e) }).collect()
+}
+
+// CHECK-LABEL: @vec_iterator_cast_deaggregate
+#[no_mangle]
+pub fn vec_iterator_cast_deaggregate(vec: Vec<Bar>) -> Vec<[u64; 4]> {
+ // FIXME These checks should be the same as other functions.
+ // CHECK-NOT: @__rust_alloc
+ // CHECK-NOT: @__rust_alloc
+
+ // 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()
+}
diff --git a/tests/codegen/vec-iter-collect-len.rs b/tests/codegen/vec-iter-collect-len.rs
new file mode 100644
index 000000000..73348ddd0
--- /dev/null
+++ b/tests/codegen/vec-iter-collect-len.rs
@@ -0,0 +1,12 @@
+// ignore-debug: the debug assertions get in the way
+// no-system-llvm
+// compile-flags: -O
+#![crate_type="lib"]
+
+#[no_mangle]
+pub fn get_len() -> usize {
+ // CHECK-LABEL: @get_len
+ // CHECK-NOT: call
+ // CHECK-NOT: invoke
+ [1, 2, 3].iter().collect::<Vec<_>>().len()
+}
diff --git a/tests/codegen/vec-optimizes-away.rs b/tests/codegen/vec-optimizes-away.rs
new file mode 100644
index 000000000..9143fad23
--- /dev/null
+++ b/tests/codegen/vec-optimizes-away.rs
@@ -0,0 +1,12 @@
+// ignore-debug: the debug assertions get in the way
+// no-system-llvm
+// compile-flags: -O
+#![crate_type="lib"]
+
+#[no_mangle]
+pub fn sum_me() -> i32 {
+ // CHECK-LABEL: @sum_me
+ // CHECK-NEXT: {{^.*:$}}
+ // CHECK-NEXT: ret i32 6
+ vec![1, 2, 3].iter().sum::<i32>()
+}
diff --git a/tests/codegen/vec-shrink-panik.rs b/tests/codegen/vec-shrink-panik.rs
new file mode 100644
index 000000000..aa6589dc3
--- /dev/null
+++ b/tests/codegen/vec-shrink-panik.rs
@@ -0,0 +1,47 @@
+// compile-flags: -O
+// ignore-debug: the debug assertions get in the way
+#![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
+
+ // Call to panic_cannot_unwind in case of double-panic is expected,
+ // but other panics are not.
+ // CHECK: cleanup
+ // CHECK-NEXT: ; call core::panicking::panic_cannot_unwind
+ // CHECK-NEXT: panic_cannot_unwind
+
+ // 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
+
+ // Call to panic_cannot_unwind in case of double-panic is expected,
+ // but other panics are not.
+ // CHECK: cleanup
+ // CHECK-NEXT: ; call core::panicking::panic_cannot_unwind
+ // CHECK-NEXT: panic_cannot_unwind
+
+ // CHECK-NOT: panic
+ iter.iter().copied().collect()
+}
+
+// CHECK: ; core::panicking::panic_cannot_unwind
+// CHECK: declare void @{{.*}}panic_cannot_unwind
diff --git a/tests/codegen/vecdeque_no_panic.rs b/tests/codegen/vecdeque_no_panic.rs
new file mode 100644
index 000000000..cbf420bad
--- /dev/null
+++ b/tests/codegen/vecdeque_no_panic.rs
@@ -0,0 +1,19 @@
+// This test checks that `VecDeque::front[_mut]()` and `VecDeque::back[_mut]()` can't panic.
+
+// compile-flags: -O
+// ignore-debug: the debug assertions get in the way
+
+#![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/virtual-function-elimination-32bit.rs b/tests/codegen/virtual-function-elimination-32bit.rs
new file mode 100644
index 000000000..6f963363a
--- /dev/null
+++ b/tests/codegen/virtual-function-elimination-32bit.rs
@@ -0,0 +1,35 @@
+// compile-flags: -Zvirtual-function-elimination -Clto -O -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/virtual-function-elimination.rs b/tests/codegen/virtual-function-elimination.rs
new file mode 100644
index 000000000..4cf7e12fe
--- /dev/null
+++ b/tests/codegen/virtual-function-elimination.rs
@@ -0,0 +1,100 @@
+// compile-flags: -Zvirtual-function-elimination -Clto -O -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"]
+#![allow(incomplete_features)]
+#![feature(unsized_locals)]
+
+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 !"NtCsfRpWlKdQPZn_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, !"NtCsfRpWlKdQPZn_28virtual_function_elimination1V"}
+// CHECK: ![[VCALL_VIS2]] = !{i64 1}
diff --git a/tests/codegen/wasm_casts_trapping.rs b/tests/codegen/wasm_casts_trapping.rs
new file mode 100644
index 000000000..eb06c4975
--- /dev/null
+++ b/tests/codegen/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/x86_64-macosx-deployment-target.rs b/tests/codegen/x86_64-macosx-deployment-target.rs
new file mode 100644
index 000000000..8e673d11d
--- /dev/null
+++ b/tests/codegen/x86_64-macosx-deployment-target.rs
@@ -0,0 +1,27 @@
+//
+// Checks that we correctly modify the target when MACOSX_DEPLOYMENT_TARGET is set.
+// See issue #60235.
+
+// compile-flags: -O --target=x86_64-apple-darwin --crate-type=rlib
+// needs-llvm-components: x86
+// rustc-env:MACOSX_DEPLOYMENT_TARGET=10.9
+#![feature(no_core, lang_items)]
+#![no_core]
+
+#[lang="sized"]
+trait Sized { }
+#[lang="freeze"]
+trait Freeze { }
+#[lang="copy"]
+trait Copy { }
+
+#[repr(C)]
+pub struct Bool {
+ b: bool,
+}
+
+// CHECK: target triple = "x86_64-apple-macosx10.9.0"
+#[no_mangle]
+pub extern "C" fn structbool() -> Bool {
+ Bool { b: true }
+}
diff --git a/tests/codegen/x86_64-no-macosx-deployment-target.rs b/tests/codegen/x86_64-no-macosx-deployment-target.rs
new file mode 100644
index 000000000..25ae6924d
--- /dev/null
+++ b/tests/codegen/x86_64-no-macosx-deployment-target.rs
@@ -0,0 +1,27 @@
+//
+// Checks that we leave the target alone when MACOSX_DEPLOYMENT_TARGET is unset.
+// See issue #60235.
+
+// compile-flags: -O --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]
+
+#[lang="sized"]
+trait Sized { }
+#[lang="freeze"]
+trait Freeze { }
+#[lang="copy"]
+trait Copy { }
+
+#[repr(C)]
+pub struct Bool {
+ b: bool,
+}
+
+// CHECK: target triple = "x86_64-apple-macosx10.7.0"
+#[no_mangle]
+pub extern "C" fn structbool() -> Bool {
+ Bool { b: true }
+}
diff --git a/tests/codegen/zip.rs b/tests/codegen/zip.rs
new file mode 100644
index 000000000..e55f4f1a2
--- /dev/null
+++ b/tests/codegen/zip.rs
@@ -0,0 +1,21 @@
+// compile-flags: -C no-prepopulate-passes -O
+
+#![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/zst-offset.rs b/tests/codegen/zst-offset.rs
new file mode 100644
index 000000000..cef4b9bda
--- /dev/null
+++ b/tests/codegen/zst-offset.rs
@@ -0,0 +1,43 @@
+// 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 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 i8, {{.+}}, [[USIZE]] 12
+ let x = &s.2;
+ witness(&x); // keep variable in an alloca
+}
+
+#[repr(simd)]
+pub struct U64x4(u64, u64, u64, u64);
+
+// 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 i8, {{.+}}, [[USIZE]] 32
+ let x = &s.1;
+ witness(&x); // keep variable in an alloca
+}
+
+#[inline(never)]
+fn witness(_: &impl Sized) {}