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