Serge Pavlov 2f81788067
[ARM][FPEnv] Lowering of fpmode intrinsics (#74054)
LLVM intrinsics `get_fpmode`, `set_fpmode` and `reset_fpmode` operate
control modes, the bits of FP environment that affect FP operations. On
ARM these bits are in FPSCR together with the status bits. The
implementation of these intrinsics produces code close to that of
functions `fegetmode` and `fesetmode` from GLIBC.

Pull request: https://github.com/llvm/llvm-project/pull/74054
2023-12-18 18:57:36 +07:00

249 lines
6.3 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -mtriple=arm-eabi -float-abi=soft -mattr=+vfp2 --verify-machineinstrs %s -o - | FileCheck %s
define void @func_02(i32 %rm) {
; CHECK-LABEL: func_02:
; CHECK: @ %bb.0:
; CHECK-NEXT: vmrs r1, fpscr
; CHECK-NEXT: sub r0, r0, #1
; CHECK-NEXT: and r0, r0, #3
; CHECK-NEXT: bic r1, r1, #12582912
; CHECK-NEXT: orr r0, r1, r0, lsl #22
; CHECK-NEXT: vmsr fpscr, r0
; CHECK-NEXT: mov pc, lr
call void @llvm.set.rounding(i32 %rm)
ret void
}
define void @func_03() {
; CHECK-LABEL: func_03:
; CHECK: @ %bb.0:
; CHECK-NEXT: vmrs r0, fpscr
; CHECK-NEXT: orr r0, r0, #12582912
; CHECK-NEXT: vmsr fpscr, r0
; CHECK-NEXT: mov pc, lr
call void @llvm.set.rounding(i32 0)
ret void
}
define void @func_04() {
; CHECK-LABEL: func_04:
; CHECK: @ %bb.0:
; CHECK-NEXT: vmrs r0, fpscr
; CHECK-NEXT: bic r0, r0, #12582912
; CHECK-NEXT: vmsr fpscr, r0
; CHECK-NEXT: mov pc, lr
call void @llvm.set.rounding(i32 1)
ret void
}
define void @func_05() {
; CHECK-LABEL: func_05:
; CHECK: @ %bb.0:
; CHECK-NEXT: vmrs r0, fpscr
; CHECK-NEXT: bic r0, r0, #12582912
; CHECK-NEXT: orr r0, r0, #4194304
; CHECK-NEXT: vmsr fpscr, r0
; CHECK-NEXT: mov pc, lr
call void @llvm.set.rounding(i32 2)
ret void
}
define void @func_06() {
; CHECK-LABEL: func_06:
; CHECK: @ %bb.0:
; CHECK-NEXT: vmrs r0, fpscr
; CHECK-NEXT: bic r0, r0, #12582912
; CHECK-NEXT: orr r0, r0, #8388608
; CHECK-NEXT: vmsr fpscr, r0
; CHECK-NEXT: mov pc, lr
call void @llvm.set.rounding(i32 3)
ret void
}
define i32 @get_fpenv_01() #0 {
; CHECK-LABEL: get_fpenv_01:
; CHECK: @ %bb.0: @ %entry
; CHECK-NEXT: .save {r11, lr}
; CHECK-NEXT: push {r11, lr}
; CHECK-NEXT: .pad #8
; CHECK-NEXT: sub sp, sp, #8
; CHECK-NEXT: add r0, sp, #4
; CHECK-NEXT: bl fegetenv
; CHECK-NEXT: ldr r0, [sp, #4]
; CHECK-NEXT: add sp, sp, #8
; CHECK-NEXT: pop {r11, lr}
; CHECK-NEXT: mov pc, lr
entry:
%fpenv = call i32 @llvm.get.fpenv.i32()
ret i32 %fpenv
}
define i32 @get_fpenv_02() nounwind {
; CHECK-LABEL: get_fpenv_02:
; CHECK: @ %bb.0: @ %entry
; CHECK-NEXT: vmrs r0, fpscr
; CHECK-NEXT: mov pc, lr
entry:
%fpenv = call i32 @llvm.get.fpenv.i32()
ret i32 %fpenv
}
define void @set_fpenv_01(i32 %fpenv) #0 {
; CHECK-LABEL: set_fpenv_01:
; CHECK: @ %bb.0: @ %entry
; CHECK-NEXT: .save {r11, lr}
; CHECK-NEXT: push {r11, lr}
; CHECK-NEXT: .pad #8
; CHECK-NEXT: sub sp, sp, #8
; CHECK-NEXT: str r0, [sp, #4]
; CHECK-NEXT: add r0, sp, #4
; CHECK-NEXT: bl fesetenv
; CHECK-NEXT: add sp, sp, #8
; CHECK-NEXT: pop {r11, lr}
; CHECK-NEXT: mov pc, lr
entry:
call void @llvm.set.fpenv.i32(i32 %fpenv)
ret void
}
define void @set_fpenv_02(i32 %fpenv) nounwind {
; CHECK-LABEL: set_fpenv_02:
; CHECK: @ %bb.0: @ %entry
; CHECK-NEXT: vmsr fpscr, r0
; CHECK-NEXT: mov pc, lr
entry:
call void @llvm.set.fpenv.i32(i32 %fpenv)
ret void
}
define void @reset_fpenv_01() #0 {
; CHECK-LABEL: reset_fpenv_01:
; CHECK: @ %bb.0: @ %entry
; CHECK-NEXT: .save {r11, lr}
; CHECK-NEXT: push {r11, lr}
; CHECK-NEXT: mvn r0, #0
; CHECK-NEXT: bl fesetenv
; CHECK-NEXT: pop {r11, lr}
; CHECK-NEXT: mov pc, lr
entry:
call void @llvm.reset.fpenv()
ret void
}
define void @reset_fpenv_02() nounwind {
; CHECK-LABEL: reset_fpenv_02:
; CHECK: @ %bb.0: @ %entry
; CHECK-NEXT: mov r0, #0
; CHECK-NEXT: vmsr fpscr, r0
; CHECK-NEXT: mov pc, lr
entry:
call void @llvm.reset.fpenv()
ret void
}
define i32 @get_fpmode_01() #0 {
; CHECK-LABEL: get_fpmode_01:
; CHECK: @ %bb.0: @ %entry
; CHECK-NEXT: .save {r11, lr}
; CHECK-NEXT: push {r11, lr}
; CHECK-NEXT: .pad #8
; CHECK-NEXT: sub sp, sp, #8
; CHECK-NEXT: add r0, sp, #4
; CHECK-NEXT: bl fegetmode
; CHECK-NEXT: ldr r0, [sp, #4]
; CHECK-NEXT: add sp, sp, #8
; CHECK-NEXT: pop {r11, lr}
; CHECK-NEXT: mov pc, lr
entry:
%fpenv = call i32 @llvm.get.fpmode.i32()
ret i32 %fpenv
}
define i32 @get_fpmode_02() nounwind {
; CHECK-LABEL: get_fpmode_02:
; CHECK: @ %bb.0: @ %entry
; CHECK-NEXT: vmrs r0, fpscr
; CHECK-NEXT: mov pc, lr
entry:
%fpenv = call i32 @llvm.get.fpmode.i32()
ret i32 %fpenv
}
define void @set_fpmode_01(i32 %fpmode) #0 {
; CHECK-LABEL: set_fpmode_01:
; CHECK: @ %bb.0: @ %entry
; CHECK-NEXT: .save {r11, lr}
; CHECK-NEXT: push {r11, lr}
; CHECK-NEXT: .pad #8
; CHECK-NEXT: sub sp, sp, #8
; CHECK-NEXT: str r0, [sp, #4]
; CHECK-NEXT: add r0, sp, #4
; CHECK-NEXT: bl fesetmode
; CHECK-NEXT: add sp, sp, #8
; CHECK-NEXT: pop {r11, lr}
; CHECK-NEXT: mov pc, lr
entry:
call void @llvm.set.fpmode.i32(i32 %fpmode)
ret void
}
define void @set_fpmode_02(i32 %fpmode) nounwind {
; CHECK-LABEL: set_fpmode_02:
; CHECK: @ %bb.0: @ %entry
; CHECK-NEXT: vmrs r1, fpscr
; CHECK-NEXT: mvn r2, #159
; CHECK-NEXT: sub r2, r2, #-134217728
; CHECK-NEXT: and r0, r0, r2
; CHECK-NEXT: mov r2, #159
; CHECK-NEXT: orr r2, r2, #-134217728
; CHECK-NEXT: and r1, r1, r2
; CHECK-NEXT: orr r0, r1, r0
; CHECK-NEXT: vmsr fpscr, r0
; CHECK-NEXT: mov pc, lr
entry:
call void @llvm.set.fpmode.i32(i32 %fpmode)
ret void
}
define void @reset_fpmode_01() #0 {
; CHECK-LABEL: reset_fpmode_01:
; CHECK: @ %bb.0: @ %entry
; CHECK-NEXT: .save {r11, lr}
; CHECK-NEXT: push {r11, lr}
; CHECK-NEXT: mvn r0, #0
; CHECK-NEXT: bl fesetmode
; CHECK-NEXT: pop {r11, lr}
; CHECK-NEXT: mov pc, lr
entry:
call void @llvm.reset.fpmode()
ret void
}
define void @reset_fpmode_02() nounwind {
; CHECK-LABEL: reset_fpmode_02:
; CHECK: @ %bb.0: @ %entry
; CHECK-NEXT: vmrs r0, fpscr
; CHECK-NEXT: ldr r1, .LCPI16_0
; CHECK-NEXT: and r0, r0, r1
; CHECK-NEXT: vmsr fpscr, r0
; CHECK-NEXT: mov pc, lr
; CHECK-NEXT: .p2align 2
; CHECK-NEXT: @ %bb.1:
; CHECK-NEXT: .LCPI16_0:
; CHECK-NEXT: .long 4160774399 @ 0xf80060ff
entry:
call void @llvm.reset.fpmode()
ret void
}
attributes #0 = { nounwind "use-soft-float"="true" }
declare void @llvm.set.rounding(i32)
declare i32 @llvm.get.fpenv.i32()
declare void @llvm.set.fpenv.i32(i32 %fpenv)
declare void @llvm.reset.fpenv()
declare i32 @llvm.get.fpmode.i32()
declare void @llvm.set.fpmode.i32(i32 %fpmode)
declare void @llvm.reset.fpmode()