| ; 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"} |