about summary refs log tree commit diff
path: root/tests/codegen/asm
diff options
context:
space:
mode:
Diffstat (limited to 'tests/codegen/asm')
-rw-r--r--tests/codegen/asm/arm64ec-clobbers.rs36
-rw-r--r--tests/codegen/asm/foo.s3
-rw-r--r--tests/codegen/asm/global_asm.rs28
-rw-r--r--tests/codegen/asm/global_asm_include.rs21
-rw-r--r--tests/codegen/asm/global_asm_x2.rs47
-rw-r--r--tests/codegen/asm/goto.rs51
-rw-r--r--tests/codegen/asm/may_unwind.rs39
-rw-r--r--tests/codegen/asm/maybe-uninit.rs27
-rw-r--r--tests/codegen/asm/msp430-clobbers.rs36
-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/s390x-clobbers.rs50
-rw-r--r--tests/codegen/asm/sanitize-llvm.rs30
-rw-r--r--tests/codegen/asm/x86-clobber_abi.rs36
-rw-r--r--tests/codegen/asm/x86-clobbers.rs20
-rw-r--r--tests/codegen/asm/x86-target-clobbers.rs29
17 files changed, 658 insertions, 0 deletions
diff --git a/tests/codegen/asm/arm64ec-clobbers.rs b/tests/codegen/asm/arm64ec-clobbers.rs
new file mode 100644
index 00000000000..2ec61907947
--- /dev/null
+++ b/tests/codegen/asm/arm64ec-clobbers.rs
@@ -0,0 +1,36 @@
+//@ assembly-output: emit-asm
+//@ compile-flags: --target arm64ec-pc-windows-msvc
+//@ needs-llvm-components: aarch64
+
+#![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: @cc_clobber
+// CHECK: call void asm sideeffect "", "~{cc}"()
+#[no_mangle]
+pub unsafe fn cc_clobber() {
+    asm!("", options(nostack, nomem));
+}
+
+// CHECK-LABEL: @no_clobber
+// CHECK: call void asm sideeffect "", ""()
+#[no_mangle]
+pub unsafe fn no_clobber() {
+    asm!("", options(nostack, nomem, preserves_flags));
+}
+
+// CHECK-LABEL: @clobber_abi
+// CHECK: asm sideeffect "", "={w0},={w1},={w2},={w3},={w4},={w5},={w6},={w7},={w8},={w9},={w10},={w11},={w12},={w15},={w16},={w17},={w30},={q0},={q1},={q2},={q3},={q4},={q5},={q6},={q7},={q8},={q9},={q10},={q11},={q12},={q13},={q14},={q15}"()
+#[no_mangle]
+pub unsafe fn clobber_abi() {
+    asm!("", clobber_abi("C"), options(nostack, nomem, preserves_flags));
+}
diff --git a/tests/codegen/asm/foo.s b/tests/codegen/asm/foo.s
new file mode 100644
index 00000000000..304d82aa0c6
--- /dev/null
+++ b/tests/codegen/asm/foo.s
@@ -0,0 +1,3 @@
+.global foo
+foo:
+    jmp baz
diff --git a/tests/codegen/asm/global_asm.rs b/tests/codegen/asm/global_asm.rs
new file mode 100644
index 00000000000..32075daa3cf
--- /dev/null
+++ b/tests/codegen/asm/global_asm.rs
@@ -0,0 +1,28 @@
+//@ revisions: x32 x64
+//@[x32] only-x86
+//@[x64] only-x86_64
+//@ compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+use std::arch::global_asm;
+
+// CHECK-LABEL: foo
+// CHECK: module asm
+// this regex will capture the correct unconditional branch inst.
+// CHECK: module asm "{{[[:space:]]+}}jmp baz"
+global_asm!(
+    r#"
+    .global foo
+foo:
+    jmp baz
+"#
+);
+
+extern "C" {
+    fn foo();
+}
+
+// CHECK-LABEL: @baz
+#[no_mangle]
+pub unsafe extern "C" fn baz() {}
diff --git a/tests/codegen/asm/global_asm_include.rs b/tests/codegen/asm/global_asm_include.rs
new file mode 100644
index 00000000000..98be9c3e333
--- /dev/null
+++ b/tests/codegen/asm/global_asm_include.rs
@@ -0,0 +1,21 @@
+//@ revisions: x32 x64
+//@[x32] only-x86
+//@[x64] only-x86_64
+//@ compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+use std::arch::global_asm;
+
+// CHECK-LABEL: foo
+// CHECK: module asm
+// CHECK: module asm "{{[[:space:]]+}}jmp baz"
+global_asm!(include_str!("foo.s"));
+
+extern "C" {
+    fn foo();
+}
+
+// CHECK-LABEL: @baz
+#[no_mangle]
+pub unsafe extern "C" fn baz() {}
diff --git a/tests/codegen/asm/global_asm_x2.rs b/tests/codegen/asm/global_asm_x2.rs
new file mode 100644
index 00000000000..9e3a00f0680
--- /dev/null
+++ b/tests/codegen/asm/global_asm_x2.rs
@@ -0,0 +1,47 @@
+//@ revisions: x32 x64
+//@[x32] only-x86
+//@[x64] only-x86_64
+//@ compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+#![no_std]
+
+use core::arch::global_asm;
+
+// CHECK-LABEL: foo
+// CHECK: module asm
+// CHECK: module asm "{{[[:space:]]+}}jmp baz"
+// any other global_asm will be appended to this first block, so:
+// CHECK-LABEL: bar
+// CHECK: module asm "{{[[:space:]]+}}jmp quux"
+global_asm!(
+    r#"
+    .global foo
+foo:
+    jmp baz
+"#
+);
+
+extern "C" {
+    fn foo();
+}
+
+// CHECK-LABEL: @baz
+#[no_mangle]
+pub unsafe extern "C" fn baz() {}
+
+// no checks here; this has been appended to the first occurrence
+global_asm!(
+    r#"
+    .global bar
+bar:
+    jmp quux
+"#
+);
+
+extern "C" {
+    fn bar();
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn quux() {}
diff --git a/tests/codegen/asm/goto.rs b/tests/codegen/asm/goto.rs
new file mode 100644
index 00000000000..e522d0da5b4
--- /dev/null
+++ b/tests/codegen/asm/goto.rs
@@ -0,0 +1,51 @@
+//@ compile-flags: -O
+//@ only-x86_64
+
+#![crate_type = "rlib"]
+#![feature(asm_goto)]
+
+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_goto
+#[no_mangle]
+pub unsafe fn asm_goto() {
+    // CHECK: callbr void asm sideeffect alignstack inteldialect "
+    // CHECK-NEXT: to label %[[FALLTHROUGHBB:[a-b0-9]+]] [label %[[JUMPBB:[a-b0-9]+]]]
+    asm!("jmp {}", label {});
+}
+
+// CHECK-LABEL: @asm_goto_with_outputs
+#[no_mangle]
+pub unsafe fn asm_goto_with_outputs() -> u64 {
+    let out: u64;
+    // CHECK: [[RES:%[0-9]+]] = callbr i64 asm sideeffect alignstack inteldialect "
+    // CHECK-NEXT: to label %[[FALLTHROUGHBB:[a-b0-9]+]] [label %[[JUMPBB:[a-b0-9]+]]]
+    asm!("{} /* {} */", out(reg) out, label { return 1; });
+    // CHECK: [[JUMPBB]]:
+    // CHECK-NEXT: [[RET:%.+]] = phi i64 [ [[RES]], %[[FALLTHROUGHBB]] ], [ 1, %start ]
+    // CHECK-NEXT: ret i64 [[RET]]
+    out
+}
+
+// CHECK-LABEL: @asm_goto_noreturn
+#[no_mangle]
+pub unsafe fn asm_goto_noreturn() -> u64 {
+    let out: u64;
+    // CHECK: callbr void asm sideeffect alignstack inteldialect "
+    // CHECK-NEXT: to label %unreachable [label %[[JUMPBB:[a-b0-9]+]]]
+    asm!("jmp {}", label { return 1; }, options(noreturn));
+    // CHECK: [[JUMPBB]]:
+    // CHECK-NEXT: ret i64 1
+    out
+}
diff --git a/tests/codegen/asm/may_unwind.rs b/tests/codegen/asm/may_unwind.rs
new file mode 100644
index 00000000000..be66b3975ff
--- /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/maybe-uninit.rs b/tests/codegen/asm/maybe-uninit.rs
new file mode 100644
index 00000000000..55813c35a46
--- /dev/null
+++ b/tests/codegen/asm/maybe-uninit.rs
@@ -0,0 +1,27 @@
+//@ compile-flags: -O
+//@ only-x86_64
+
+#![crate_type = "rlib"]
+#![allow(asm_sub_register)]
+
+use std::arch::asm;
+use std::mem::MaybeUninit;
+
+// CHECK-LABEL: @int
+#[no_mangle]
+pub unsafe fn int(x: MaybeUninit<i32>) -> MaybeUninit<i32> {
+    let y: MaybeUninit<i32>;
+    asm!("/*{}{}*/", in(reg) x, out(reg) y);
+    y
+}
+
+// CHECK-LABEL: @inout
+#[no_mangle]
+pub unsafe fn inout(mut x: i32) -> MaybeUninit<u32> {
+    let mut y: MaybeUninit<u32>;
+    asm!("/*{}*/", inout(reg) x => y);
+    asm!("/*{}*/", inout(reg) y => x);
+    asm!("/*{}*/", inlateout(reg) x => y);
+    asm!("/*{}*/", inlateout(reg) y => x);
+    y
+}
diff --git a/tests/codegen/asm/msp430-clobbers.rs b/tests/codegen/asm/msp430-clobbers.rs
new file mode 100644
index 00000000000..c00c04f3088
--- /dev/null
+++ b/tests/codegen/asm/msp430-clobbers.rs
@@ -0,0 +1,36 @@
+//@ assembly-output: emit-asm
+//@ compile-flags: --target msp430-none-elf
+//@ needs-llvm-components: msp430
+
+#![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: @sr_clobber
+// CHECK: call void asm sideeffect "", "~{sr}"()
+#[no_mangle]
+pub unsafe fn sr_clobber() {
+    asm!("", options(nostack, nomem));
+}
+
+// CHECK-LABEL: @no_clobber
+// CHECK: call void asm sideeffect "", ""()
+#[no_mangle]
+pub unsafe fn no_clobber() {
+    asm!("", options(nostack, nomem, preserves_flags));
+}
+
+// CHECK-LABEL: @clobber_abi
+// CHECK: asm sideeffect "", "={r11},={r12},={r13},={r14},={r15}"()
+#[no_mangle]
+pub unsafe fn clobber_abi() {
+    asm!("", clobber_abi("C"), options(nostack, nomem, preserves_flags));
+}
diff --git a/tests/codegen/asm/multiple-options.rs b/tests/codegen/asm/multiple-options.rs
new file mode 100644
index 00000000000..1ee295e32c9
--- /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 00000000000..96a72c2f5ae
--- /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 00000000000..0be1b66bd99
--- /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/s390x-clobbers.rs b/tests/codegen/asm/s390x-clobbers.rs
new file mode 100644
index 00000000000..45f72206bdf
--- /dev/null
+++ b/tests/codegen/asm/s390x-clobbers.rs
@@ -0,0 +1,50 @@
+//@ revisions: s390x
+//@[s390x] compile-flags: --target s390x-unknown-linux-gnu
+//@[s390x] needs-llvm-components: systemz
+
+#![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: @cc_clobber
+// CHECK: call void asm sideeffect "", "~{cc}"()
+#[no_mangle]
+pub unsafe fn cc_clobber() {
+    asm!("", options(nostack, nomem));
+}
+
+// CHECK-LABEL: @no_clobber
+// CHECK: call void asm sideeffect "", ""()
+#[no_mangle]
+pub unsafe fn no_clobber() {
+    asm!("", options(nostack, nomem, preserves_flags));
+}
+
+// CHECK-LABEL: @a2_clobber
+// CHECK: call void asm sideeffect "", "~{a2}"()
+#[no_mangle]
+pub unsafe fn a2_clobber() {
+    asm!("", out("a2") _, options(nostack, nomem, preserves_flags));
+}
+
+// CHECK-LABEL: @v0_clobber
+// CHECK: call void asm sideeffect "", "~{v0}"()
+#[no_mangle]
+pub unsafe fn v0_clobber() {
+    asm!("", out("v0") _, options(nostack, nomem, preserves_flags));
+}
+
+// CHECK-LABEL: @clobber_abi
+// CHECK: asm sideeffect "", "={r0},={r1},={r2},={r3},={r4},={r5},={r14},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},~{v0},~{v1},~{v2},~{v3},~{v4},~{v5},~{v6},~{v7},~{v8},~{v9},~{v10},~{v11},~{v12},~{v13},~{v14},~{v15},~{v16},~{v17},~{v18},~{v19},~{v20},~{v21},~{v22},~{v23},~{v24},~{v25},~{v26},~{v27},~{v28},~{v29},~{v30},~{v31},~{a2},~{a3},~{a4},~{a5},~{a6},~{a7},~{a8},~{a9},~{a10},~{a11},~{a12},~{a13},~{a14},~{a15}"()
+#[no_mangle]
+pub unsafe fn clobber_abi() {
+    asm!("", clobber_abi("C"), options(nostack, nomem, preserves_flags));
+}
diff --git a/tests/codegen/asm/sanitize-llvm.rs b/tests/codegen/asm/sanitize-llvm.rs
new file mode 100644
index 00000000000..fb332f9a0f3
--- /dev/null
+++ b/tests/codegen/asm/sanitize-llvm.rs
@@ -0,0 +1,30 @@
+// FIXME(nagisa): remove the flags below once all targets support `asm!`.
+//@ compile-flags: --target x86_64-unknown-linux-gnu -Copt-level=0
+//@ needs-llvm-components: x86
+
+// Verify we sanitize the special tokens for the LLVM inline-assembly, ensuring people won't
+// inadvertently rely on the LLVM-specific syntax and features.
+#![no_core]
+#![feature(no_core, 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/x86-clobber_abi.rs b/tests/codegen/asm/x86-clobber_abi.rs
new file mode 100644
index 00000000000..cc563474bf8
--- /dev/null
+++ b/tests/codegen/asm/x86-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/x86-clobbers.rs b/tests/codegen/asm/x86-clobbers.rs
new file mode 100644
index 00000000000..4094db74134
--- /dev/null
+++ b/tests/codegen/asm/x86-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/x86-target-clobbers.rs b/tests/codegen/asm/x86-target-clobbers.rs
new file mode 100644
index 00000000000..119372491ff
--- /dev/null
+++ b/tests/codegen/asm/x86-target-clobbers.rs
@@ -0,0 +1,29 @@
+//@ only-x86_64
+//@ revisions: base avx512
+//@ [avx512]compile-flags: -C target-feature=+avx512f
+
+#![crate_type = "rlib"]
+
+use std::arch::asm;
+
+// CHECK-LABEL: @amx_clobber
+// base: call void asm sideeffect inteldialect "", "~{tmm0}"()
+#[no_mangle]
+pub unsafe fn amx_clobber() {
+    asm!("", out("tmm0") _, options(nostack, nomem, preserves_flags));
+}
+
+// CHECK-LABEL: @avx512_clobber
+// base: call void asm sideeffect inteldialect "", "~{xmm31}"()
+// avx512: call float asm sideeffect inteldialect "", "=&{xmm31}"()
+#[no_mangle]
+pub unsafe fn avx512_clobber() {
+    asm!("", out("zmm31") _, options(nostack, nomem, preserves_flags));
+}
+
+// CHECK-LABEL: @eax_clobber
+// CHECK: call i32 asm sideeffect inteldialect "", "=&{ax}"()
+#[no_mangle]
+pub unsafe fn eax_clobber() {
+    asm!("", out("eax") _, options(nostack, nomem, preserves_flags));
+}