1 /*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #ifndef BERBERIS_INTRINSICS_GUEST_RISCV64_FPSTATE_H_
18 #define BERBERIS_INTRINSICS_GUEST_RISCV64_FPSTATE_H_
19
20 #include <cfenv>
21 #include <cstdint>
22
23 #include "berberis/base/checks.h"
24 #include "berberis/intrinsics/guest_rounding_modes.h"
25
26 namespace berberis {
27
28 namespace FPFlags {
29
30 inline constexpr uint64_t NV = 1 << 4;
31 inline constexpr uint64_t DZ = 1 << 3;
32 inline constexpr uint64_t OF = 1 << 2;
33 inline constexpr uint64_t UF = 1 << 1;
34 inline constexpr uint64_t NX = 1 << 0;
35 inline constexpr uint64_t RM_POS = 5;
36 inline constexpr uint64_t RM_MASK = 0b111;
37 inline constexpr uint64_t RM_MAX = 0b100;
38 inline constexpr uint64_t RNE = 0b000;
39 inline constexpr uint64_t RTZ = 0b001;
40 inline constexpr uint64_t RDN = 0b010;
41 inline constexpr uint64_t RUP = 0b011;
42 inline constexpr uint64_t RMM = 0b100;
43 inline constexpr uint64_t DYN = 0b111;
44
45 } // namespace FPFlags
46
47 namespace VXRMFlags {
48
49 inline constexpr uint64_t RNU = 0b00;
50 inline constexpr uint64_t RNE = 0b01;
51 inline constexpr uint64_t RDN = 0b10;
52 inline constexpr uint64_t ROD = 0b11;
53
54 } // namespace VXRMFlags
55
56 namespace intrinsics {
57
58 // Note that not all RISC-V rounding modes are supported on popular architectures.
59 // FE_TIESAWAY is emulated, but proper emulation needs FE_TOWARDZERO mode.
ToHostRoundingMode(int8_t rm)60 inline int ToHostRoundingMode(int8_t rm) {
61 if (rm == FPFlags::DYN) {
62 return FE_HOSTROUND;
63 }
64 CHECK_GE(rm, 0);
65 CHECK_LE(rm, int8_t{FPFlags::RM_MAX});
66 static constexpr int kRounding[FPFlags::RM_MAX + 1] = {
67 FE_TONEAREST, FE_TOWARDZERO, FE_DOWNWARD, FE_UPWARD, FE_TOWARDZERO};
68 return kRounding[rm];
69 }
70
71 // Same as ToHostRoundingMode, but returns pseudo FE_TIESAWAY mode for RMM.
ToIntrinsicRoundingMode(int8_t rm)72 inline int ToIntrinsicRoundingMode(int8_t rm) {
73 if (rm == FPFlags::RMM) {
74 return FE_TIESAWAY;
75 }
76 return ToHostRoundingMode(rm);
77 }
78
GuestModeFromHostRounding()79 inline uint8_t GuestModeFromHostRounding() {
80 switch (fegetround()) {
81 case FE_TONEAREST:
82 return FPFlags::RNE;
83 case FE_DOWNWARD:
84 return FPFlags::RDN;
85 case FE_UPWARD:
86 return FPFlags::RUP;
87 case FE_TOWARDZERO:
88 return FPFlags::RTZ;
89 default:
90 CHECK(false);
91 }
92 }
93
94 } // namespace intrinsics
95
96 } // namespace berberis
97
98 #endif // BERBERIS_INTRINSICS_GUEST_RISCV64_FPSTATE_H_
99