1 /* This file is part of the dynarmic project.
2 * Copyright (c) 2018 MerryMage
3 * SPDX-License-Identifier: 0BSD
4 */
5
6 #include "frontend/A64/translate/impl/impl.h"
7
8 namespace Dynarmic::A64 {
9
FMOV_float(Imm<2> type,Vec Vn,Vec Vd)10 bool TranslatorVisitor::FMOV_float(Imm<2> type, Vec Vn, Vec Vd) {
11 const auto datasize = FPGetDataSize(type);
12 if (!datasize) {
13 return UnallocatedEncoding();
14 }
15
16 const IR::U16U32U64 operand = V_scalar(*datasize, Vn);
17
18 V_scalar(*datasize, Vd, operand);
19 return true;
20 }
21
FABS_float(Imm<2> type,Vec Vn,Vec Vd)22 bool TranslatorVisitor::FABS_float(Imm<2> type, Vec Vn, Vec Vd) {
23 const auto datasize = FPGetDataSize(type);
24 if (!datasize) {
25 return UnallocatedEncoding();
26 }
27
28 const IR::U16U32U64 operand = V_scalar(*datasize, Vn);
29 const IR::U16U32U64 result = ir.FPAbs(operand);
30 V_scalar(*datasize, Vd, result);
31 return true;
32 }
33
FNEG_float(Imm<2> type,Vec Vn,Vec Vd)34 bool TranslatorVisitor::FNEG_float(Imm<2> type, Vec Vn, Vec Vd) {
35 const auto datasize = FPGetDataSize(type);
36 if (!datasize) {
37 return UnallocatedEncoding();
38 }
39
40 const IR::U16U32U64 operand = V_scalar(*datasize, Vn);
41 const IR::U16U32U64 result = ir.FPNeg(operand);
42 V_scalar(*datasize, Vd, result);
43 return true;
44 }
45
FSQRT_float(Imm<2> type,Vec Vn,Vec Vd)46 bool TranslatorVisitor::FSQRT_float(Imm<2> type, Vec Vn, Vec Vd) {
47 const auto datasize = FPGetDataSize(type);
48 if (!datasize || *datasize == 16) {
49 return UnallocatedEncoding();
50 }
51
52 const IR::U32U64 operand = V_scalar(*datasize, Vn);
53 const IR::U32U64 result = ir.FPSqrt(operand);
54 V_scalar(*datasize, Vd, result);
55 return true;
56 }
57
FMOV_float_imm(Imm<2> type,Imm<8> imm8,Vec Vd)58 bool TranslatorVisitor::FMOV_float_imm(Imm<2> type, Imm<8> imm8, Vec Vd) {
59 const auto datasize = FPGetDataSize(type);
60 if (!datasize) {
61 return UnallocatedEncoding();
62 }
63
64 IR::UAny result = [&]() -> IR::UAny {
65 switch (*datasize) {
66 case 16: {
67 const u16 sign = imm8.Bit<7>() ? 1 : 0;
68 const u16 exp = (imm8.Bit<6>() ? 0b0'1100 : 0b1'0000) | imm8.Bits<4, 5, u16>();
69 const u16 fract = imm8.Bits<0, 3, u16>() << 6;
70 return ir.Imm16((sign << 15) | (exp << 10) | fract);
71 }
72 case 32: {
73 const u32 sign = imm8.Bit<7>() ? 1 : 0;
74 const u32 exp = (imm8.Bit<6>() ? 0b0111'1100 : 0b1000'0000) | imm8.Bits<4, 5, u32>();
75 const u32 fract = imm8.Bits<0, 3, u32>() << 19;
76 return ir.Imm32((sign << 31) | (exp << 23) | fract);
77 }
78 case 64:
79 default: {
80 const u64 sign = imm8.Bit<7>() ? 1 : 0;
81 const u64 exp = (imm8.Bit<6>() ? 0b011'1111'1100 : 0b100'0000'0000) | imm8.Bits<4, 5, u64>();
82 const u64 fract = imm8.Bits<0, 3, u64>() << 48;
83 return ir.Imm64((sign << 63) | (exp << 52) | fract);
84 }
85 }
86 }();
87
88 V_scalar(*datasize, Vd, result);
89 return true;
90 }
91
FCVT_float(Imm<2> type,Imm<2> opc,Vec Vn,Vec Vd)92 bool TranslatorVisitor::FCVT_float(Imm<2> type, Imm<2> opc, Vec Vn, Vec Vd) {
93 if (type == opc) {
94 return UnallocatedEncoding();
95 }
96
97 const auto srcsize = FPGetDataSize(type);
98 const auto dstsize = FPGetDataSize(opc);
99
100 if (!srcsize || !dstsize) {
101 return UnallocatedEncoding();
102 }
103
104 const IR::UAny operand = V_scalar(*srcsize, Vn);
105 const auto rounding_mode = ir.current_location->FPCR().RMode();
106
107 IR::UAny result;
108 switch (*srcsize) {
109 case 16:
110 switch (*dstsize) {
111 case 32:
112 result = ir.FPHalfToSingle(operand, rounding_mode);
113 break;
114 case 64:
115 result = ir.FPHalfToDouble(operand, rounding_mode);
116 break;
117 }
118 break;
119 case 32:
120 switch (*dstsize) {
121 case 16:
122 result = ir.FPSingleToHalf(operand, rounding_mode);
123 break;
124 case 64:
125 result = ir.FPSingleToDouble(operand, rounding_mode);
126 break;
127 }
128 break;
129 case 64:
130 switch (*dstsize) {
131 case 16:
132 result = ir.FPDoubleToHalf(operand, rounding_mode);
133 break;
134 case 32:
135 result = ir.FPDoubleToSingle(operand, rounding_mode);
136 break;
137 }
138 break;
139 }
140
141 V_scalar(*dstsize, Vd, result);
142
143 return true;
144 }
145
FloatingPointRoundToIntegral(TranslatorVisitor & v,Imm<2> type,Vec Vn,Vec Vd,FP::RoundingMode rounding_mode,bool exact)146 static bool FloatingPointRoundToIntegral(TranslatorVisitor& v, Imm<2> type, Vec Vn, Vec Vd,
147 FP::RoundingMode rounding_mode, bool exact) {
148 const auto datasize = FPGetDataSize(type);
149 if (!datasize) {
150 return v.UnallocatedEncoding();
151 }
152
153 const IR::U16U32U64 operand = v.V_scalar(*datasize, Vn);
154 const IR::U16U32U64 result = v.ir.FPRoundInt(operand, rounding_mode, exact);
155 v.V_scalar(*datasize, Vd, result);
156 return true;
157 }
158
FRINTN_float(Imm<2> type,Vec Vn,Vec Vd)159 bool TranslatorVisitor::FRINTN_float(Imm<2> type, Vec Vn, Vec Vd) {
160 return FloatingPointRoundToIntegral(*this, type, Vn, Vd, FP::RoundingMode::ToNearest_TieEven, false);
161 }
162
FRINTP_float(Imm<2> type,Vec Vn,Vec Vd)163 bool TranslatorVisitor::FRINTP_float(Imm<2> type, Vec Vn, Vec Vd) {
164 return FloatingPointRoundToIntegral(*this, type, Vn, Vd, FP::RoundingMode::TowardsPlusInfinity, false);
165 }
166
FRINTM_float(Imm<2> type,Vec Vn,Vec Vd)167 bool TranslatorVisitor::FRINTM_float(Imm<2> type, Vec Vn, Vec Vd) {
168 return FloatingPointRoundToIntegral(*this, type, Vn, Vd, FP::RoundingMode::TowardsMinusInfinity, false);
169 }
170
FRINTZ_float(Imm<2> type,Vec Vn,Vec Vd)171 bool TranslatorVisitor::FRINTZ_float(Imm<2> type, Vec Vn, Vec Vd) {
172 return FloatingPointRoundToIntegral(*this, type, Vn, Vd, FP::RoundingMode::TowardsZero, false);
173 }
174
FRINTA_float(Imm<2> type,Vec Vn,Vec Vd)175 bool TranslatorVisitor::FRINTA_float(Imm<2> type, Vec Vn, Vec Vd) {
176 return FloatingPointRoundToIntegral(*this, type, Vn, Vd, FP::RoundingMode::ToNearest_TieAwayFromZero, false);
177 }
178
FRINTX_float(Imm<2> type,Vec Vn,Vec Vd)179 bool TranslatorVisitor::FRINTX_float(Imm<2> type, Vec Vn, Vec Vd) {
180 return FloatingPointRoundToIntegral(*this, type, Vn, Vd, ir.current_location->FPCR().RMode(), true);
181 }
182
FRINTI_float(Imm<2> type,Vec Vn,Vec Vd)183 bool TranslatorVisitor::FRINTI_float(Imm<2> type, Vec Vn, Vec Vd) {
184 return FloatingPointRoundToIntegral(*this, type, Vn, Vd, ir.current_location->FPCR().RMode(), false);
185 }
186
187 } // namespace Dynarmic::A64
188