| ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5 | |
| ; RUN: llc -mtriple=aarch64 -fast-isel=0 -global-isel=false -verify-machineinstrs < %s | FileCheck %s | |
| ; Tests for llvm.write_volatile_register on AArch64. | |
| ; | |
| ; Unlike llvm.write_register, the volatile variant carries IntrHasSideEffects | |
| ; and emits a FAKE_USE of the target physical register after the WRITE_REGISTER. | |
| ; The FAKE_USE prevents the CopyToReg from being dead-eliminated while avoiding | |
| ; an extra cross-domain read (fmov xN, dM) that would arise if we kept the | |
| ; register live via READ_REGISTER + CopyFromReg instead. | |
| ; | |
| ; For Windows-specific tests with reserved GP register x18 see | |
| ; clang/test/CodeGen/arm64-microsoft-intrinsics.c. | |
| ; -- Stack pointer ----------------------------------------------------------- | |
| ; sp is the canonical GP test: it is always accessible regardless of ABI. | |
| define void @write_volatile_sp(i64 %val) { | |
| ; CHECK-LABEL: write_volatile_sp: | |
| ; CHECK: // %bb.0: | |
| ; CHECK-NEXT: mov sp, x0 | |
| ; CHECK-NEXT: // fake_use: $sp | |
| ; CHECK-NEXT: ret | |
| call void @llvm.write_volatile_register.i64(metadata !0, i64 %val) | |
| ret void | |
| } | |
| ; -- FP/SIMD d-registers: integer bit-pattern -> FP register ----------------- | |
| ; | |
| ; The caller passes an i64 bit-pattern (e.g. obtained from read_volatile_register). | |
| ; Writing it into a SIMD d-register requires a cross-domain integer->FP move | |
| ; (fmov dN, xM). The FAKE_USE ensures the CopyToReg is not dead-eliminated | |
| ; even though dN has no further GP-domain uses in this function. | |
| define void @write_volatile_d5(i64 %bits) { | |
| ; CHECK-LABEL: write_volatile_d5: | |
| ; CHECK: // %bb.0: | |
| ; CHECK-NEXT: fmov d5, x0 | |
| ; CHECK-NEXT: // fake_use: $d5 | |
| ; CHECK-NEXT: ret | |
| call void @llvm.write_volatile_register.i64(metadata !1, i64 %bits) | |
| ret void | |
| } | |
| define void @write_volatile_d31(i64 %bits) { | |
| ; CHECK-LABEL: write_volatile_d31: | |
| ; CHECK: // %bb.0: | |
| ; CHECK-NEXT: fmov d31, x0 | |
| ; CHECK-NEXT: // fake_use: $d31 | |
| ; CHECK-NEXT: ret | |
| call void @llvm.write_volatile_register.i64(metadata !2, i64 %bits) | |
| ret void | |
| } | |
| ; -- Back-to-back writes must both survive ------------------------------------ | |
| ; | |
| ; Each call carries IntrHasSideEffects so neither may be suppressed on behalf | |
| ; of the other. Verify that both fmov + fake_use pairs appear in order. | |
| define void @write_volatile_d5_twice(i64 %a, i64 %b) { | |
| ; CHECK-LABEL: write_volatile_d5_twice: | |
| ; CHECK: // %bb.0: | |
| ; CHECK-NEXT: fmov d5, x0 | |
| ; CHECK-NEXT: // fake_use: $d5 | |
| ; CHECK-NEXT: fmov d5, x1 | |
| ; CHECK-NEXT: // fake_use: $d5 | |
| ; CHECK-NEXT: ret | |
| call void @llvm.write_volatile_register.i64(metadata !1, i64 %a) | |
| call void @llvm.write_volatile_register.i64(metadata !1, i64 %b) | |
| ret void | |
| } | |
| declare void @llvm.write_volatile_register.i64(metadata, i64) | |
| !0 = !{!"sp"} | |
| !1 = !{!"d5"} | |
| !2 = !{!"d31"} |