ARM64 emitter/disasm: More scalar FPU instructions

This commit is contained in:
Henrik Rydgard 2015-03-21 21:18:26 +01:00
parent ff758f58ad
commit 9a5a093105
4 changed files with 99 additions and 2 deletions

View file

@ -2697,6 +2697,50 @@ void ARM64FloatEmitter::FDIV(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm)
{
Emit2Source(0, 0, IsDouble(Rd), 1, Rd, Rn, Rm);
}
void ARM64FloatEmitter::FMAX(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm)
{
Emit2Source(0, 0, IsDouble(Rd), 4, Rd, Rn, Rm);
}
void ARM64FloatEmitter::FMIN(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm)
{
Emit2Source(0, 0, IsDouble(Rd), 5, Rd, Rn, Rm);
}
void ARM64FloatEmitter::FMAXNM(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm)
{
Emit2Source(0, 0, IsDouble(Rd), 6, Rd, Rn, Rm);
}
void ARM64FloatEmitter::FMINNM(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm)
{
Emit2Source(0, 0, IsDouble(Rd), 7, Rd, Rn, Rm);
}
void ARM64FloatEmitter::FNMUL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm)
{
Emit2Source(0, 0, IsDouble(Rd), 8, Rd, Rn, Rm);
}
void ARM64FloatEmitter::FMADD(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra) {
Emit3Source(IsDouble(Rd), Rd, Rn, Rm, Ra, 0);
}
void ARM64FloatEmitter::FMSUB(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra) {
Emit3Source(IsDouble(Rd), Rd, Rn, Rm, Ra, 1);
}
void ARM64FloatEmitter::FNMADD(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra) {
Emit3Source(IsDouble(Rd), Rd, Rn, Rm, Ra, 2);
}
void ARM64FloatEmitter::FNMSUB(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra) {
Emit3Source(IsDouble(Rd), Rd, Rn, Rm, Ra, 3);
}
void ARM64FloatEmitter::Emit3Source(bool isDouble, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra, int opcode) {
int type = isDouble ? 1 : 0;
Rd = DecodeReg(Rd);
Rn = DecodeReg(Rn);
Rm = DecodeReg(Rm);
Ra = DecodeReg(Ra);
int o1 = opcode >> 1;
int o0 = opcode & 1;
m_emit->Write32((0x1F << 24) | (type << 22) | (o1 << 21) | (Rm << 16) | (o0 << 15) | (Ra << 10) | (Rn << 5) | Rd);
}
// Scalar floating point immediate
void ARM64FloatEmitter::FMOV(ARM64Reg Rd, u32 imm)
@ -3366,6 +3410,25 @@ bool ARM64XEmitter::TryEORI2R(ARM64Reg Rd, ARM64Reg Rn, u32 imm) {
}
}
void ARM64FloatEmitter::MOVI2F(ARM64Reg Rd, float value, ARM64Reg scratch, bool negate) {
_assert_msg_(JIT, !IsDouble(Rd), "MOVI2F does not yet support double precision");
if (value == 0.0) {
FMOV(Rd, 0);
if (negate) {
FNEG(Rd, Rd);
}
// TODO: There are some other values we could generate with the float-imm instruction, like 1.0...
} else {
_assert_msg_(JIT, scratch != INVALID_REG, "Failed to find a way to generate FP immediate %f without scratch", value);
u32 ival;
if (negate) {
value = -value;
}
memcpy(&ival, &value, sizeof(ival));
m_emit->MOVI2R(scratch, ival);
FMOV(Rd, scratch);
}
}
void ARM64XEmitter::SUBSI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch) {
u32 val;

View file

@ -13,6 +13,13 @@
#define DYNA_REC JIT
#ifdef FMAX
#undef FMAX
#endif
#ifdef FMIN
#undef FMIN
#endif
namespace Arm64Gen
{
@ -765,6 +772,17 @@ public:
void FMUL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm);
void FSUB(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm);
void FDIV(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm);
void FMAX(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm);
void FMIN(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm);
void FMAXNM(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm);
void FMINNM(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm);
void FNMUL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm);
// Scalar - 3 Source. Note - the accumulator is last on ARM!
void FMADD(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra);
void FMSUB(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra);
void FNMADD(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra);
void FNMSUB(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra);
// Scalar floating point immediate
void FMOV(ARM64Reg Rd, u32 imm);
@ -852,6 +870,8 @@ public:
// vector x indexed element
void FMUL(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, u8 index);
void MOVI2F(ARM64Reg Rd, float value, ARM64Reg scratch = INVALID_REG, bool negate = false);
// ABI related
void ABI_PushRegisters(BitSet32 registers);
void ABI_PopRegisters(BitSet32 registers, BitSet32 ignore_mask = BitSet32(0));
@ -881,6 +901,7 @@ private:
void EmitVectorxElement(bool U, u32 size, bool L, u32 opcode, bool H, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm);
void EmitLoadStoreUnscaled(u32 size, u32 op, ARM64Reg Rt, ARM64Reg Rn, s32 imm);
void EmitConvertScalarToInt(ARM64Reg Rd, ARM64Reg Rn, RoundingMode round, bool sign);
void Emit3Source(bool isDouble, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra, int opcode);
};
class ARM64CodeBlock : public CodeBlock<ARM64XEmitter>

View file

@ -518,8 +518,13 @@ static void FPandASIMD2(uint32_t w, uint64_t addr, Instruction *instr) {
} else if (((w >> 10) & 3) == 3) {
snprintf(instr->text, sizeof(instr->text), "(float cond select %08x)", w);
}
} else if (((w >> 21) & 0x2F9) == 0xF8) {
snprintf(instr->text, sizeof(instr->text), "(float data 3-source %08x)", w);
} else if (((w >> 21) & 0x2F8) == 0xF8) {
int opcode = ((w >> 15) & 1) | ((w >> 20) & 2);
const char *opnames[9] = { "fmadd", "fmsub", "fnmadd", "fnmsub" };
int size = (w >> 22) & 1;
char r = size ? 'd' : 's';
int Ra = (w >> 10) & 0x1f;
snprintf(instr->text, sizeof(instr->text), "%s %c%d, %c%d, %c%d, %c%d", opnames[opcode], r, Rd, r, Rn, r, Rm, r, Ra);
} else if (((w >> 21) & 0x2F9) == 0x2F1) {
if (((w >> 10) & 3) == 0) {
snprintf(instr->text, sizeof(instr->text), "(asimd scalar three different %08x)", w);

View file

@ -38,6 +38,14 @@ bool TestArm64Emitter() {
//emitter.EXTR(W1, W3, 0, 7);
//RET(CheckLast(emitter, "53033061 extr w1, w3, w7"));
fp.FMADD(S1, S2, S3, S4);
RET(CheckLast(emitter, "1f031041 fmadd s1, s2, s3, s4"));
fp.FNMSUB(D1, D2, D3, D4);
RET(CheckLast(emitter, "1f639041 fnmsub d1, d2, d3, d4"));
fp.FMAX(S1, S2, S3);
RET(CheckLast(emitter, "1e234841 fmax s1, s2, s3"));
fp.FNMUL(D1, D2, D3);
RET(CheckLast(emitter, "1e638841 fnmul d1, d2, d3"));
fp.SCVTF(S13, W7);
RET(CheckLast(emitter, "1e2200ed scvtf s13, w7"));
emitter.UBFM(W1, W3, 0, 7);