A64: Implement EXTR
This commit is contained in:
parent
e1fd6038a2
commit
7734cf1050
6 changed files with 61 additions and 1 deletions
|
@ -176,6 +176,26 @@ void EmitX64::EmitConditionalSelect64(EmitContext& ctx, IR::Inst* inst) {
|
||||||
EmitConditionalSelect(code, ctx, inst, 64);
|
EmitConditionalSelect(code, ctx, inst, 64);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void EmitExtractRegister(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, int bit_size) {
|
||||||
|
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||||
|
|
||||||
|
const Xbyak::Reg result = ctx.reg_alloc.UseScratchGpr(args[0]).changeBit(bit_size);
|
||||||
|
const Xbyak::Reg operand = ctx.reg_alloc.UseScratchGpr(args[1]).changeBit(bit_size);
|
||||||
|
const u8 lsb = args[2].GetImmediateU8();
|
||||||
|
|
||||||
|
code.shrd(result, operand, lsb);
|
||||||
|
|
||||||
|
ctx.reg_alloc.DefineValue(inst, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmitX64::EmitExtractRegister32(Dynarmic::BackendX64::EmitContext& ctx, IR::Inst* inst) {
|
||||||
|
EmitExtractRegister(*code, ctx, inst, 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmitX64::EmitExtractRegister64(Dynarmic::BackendX64::EmitContext& ctx, IR::Inst* inst) {
|
||||||
|
EmitExtractRegister(*code, ctx, inst, 64);
|
||||||
|
}
|
||||||
|
|
||||||
void EmitX64::EmitLogicalShiftLeft32(EmitContext& ctx, IR::Inst* inst) {
|
void EmitX64::EmitLogicalShiftLeft32(EmitContext& ctx, IR::Inst* inst) {
|
||||||
auto carry_inst = inst->GetAssociatedPseudoOperation(IR::Opcode::GetCarryFromOp);
|
auto carry_inst = inst->GetAssociatedPseudoOperation(IR::Opcode::GetCarryFromOp);
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ INST(BFM, "BFM", "z0110
|
||||||
INST(UBFM, "UBFM", "z10100110Nrrrrrrssssssnnnnnddddd")
|
INST(UBFM, "UBFM", "z10100110Nrrrrrrssssssnnnnnddddd")
|
||||||
|
|
||||||
// Data processing - Immediate - Extract
|
// Data processing - Immediate - Extract
|
||||||
//INST(EXTR, "EXTR", "z00100111N0mmmmmssssssnnnnnddddd")
|
INST(EXTR, "EXTR", "z00100111N0mmmmmssssssnnnnnddddd")
|
||||||
|
|
||||||
// Conditional branch
|
// Conditional branch
|
||||||
INST(B_cond, "B.cond", "01010100iiiiiiiiiiiiiiiiiii0cccc")
|
INST(B_cond, "B.cond", "01010100iiiiiiiiiiiiiiiiiii0cccc")
|
||||||
|
|
|
@ -76,4 +76,23 @@ bool TranslatorVisitor::UBFM(bool sf, bool N, Imm<6> immr, Imm<6> imms, Reg Rn,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TranslatorVisitor::EXTR(bool sf, bool N, Reg Rm, Imm<6> imms, Reg Rn, Reg Rd) {
|
||||||
|
if (N != sf) {
|
||||||
|
return UnallocatedEncoding();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sf && imms.Bit<5>()) {
|
||||||
|
return ReservedValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t datasize = sf ? 64 : 32;
|
||||||
|
|
||||||
|
const IR::U32U64 m = X(datasize, Rm);
|
||||||
|
const IR::U32U64 n = X(datasize, Rn);
|
||||||
|
const IR::U32U64 result = ir.ExtractRegister(m, n, ir.Imm8(imms.ZeroExtend<u8>()));
|
||||||
|
|
||||||
|
X(datasize, Rd, result);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Dynarmic::A64
|
} // namespace Dynarmic::A64
|
||||||
|
|
|
@ -481,6 +481,22 @@ U32U64 IREmitter::CountLeadingZeros(const U32U64& a) {
|
||||||
return Inst<U64>(Opcode::CountLeadingZeros64, a);
|
return Inst<U64>(Opcode::CountLeadingZeros64, a);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
U32 IREmitter::ExtractRegister(const U32& a, const U32& b, const U8& lsb) {
|
||||||
|
return Inst<U32>(Opcode::ExtractRegister32, a, b, lsb);
|
||||||
|
}
|
||||||
|
|
||||||
|
U64 IREmitter::ExtractRegister(const U64& a, const U64& b, const U8& lsb) {
|
||||||
|
return Inst<U64>(Opcode::ExtractRegister64, a, b, lsb);
|
||||||
|
}
|
||||||
|
|
||||||
|
U32U64 IREmitter::ExtractRegister(const U32U64& a, const U32U64& b, const U8& lsb) {
|
||||||
|
if (a.GetType() == IR::Type::U32) {
|
||||||
|
return Inst<U32>(Opcode::ExtractRegister32, a, b, lsb);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Inst<U64>(Opcode::ExtractRegister64, a, b, lsb);
|
||||||
|
}
|
||||||
|
|
||||||
ResultAndOverflow<U32> IREmitter::SignedSaturatedAdd(const U32& a, const U32& b) {
|
ResultAndOverflow<U32> IREmitter::SignedSaturatedAdd(const U32& a, const U32& b) {
|
||||||
auto result = Inst<U32>(Opcode::SignedSaturatedAdd, a, b);
|
auto result = Inst<U32>(Opcode::SignedSaturatedAdd, a, b);
|
||||||
auto overflow = Inst<U1>(Opcode::GetOverflowFromOp, result);
|
auto overflow = Inst<U1>(Opcode::GetOverflowFromOp, result);
|
||||||
|
|
|
@ -142,6 +142,9 @@ public:
|
||||||
U32 CountLeadingZeros(const U32& a);
|
U32 CountLeadingZeros(const U32& a);
|
||||||
U64 CountLeadingZeros(const U64& a);
|
U64 CountLeadingZeros(const U64& a);
|
||||||
U32U64 CountLeadingZeros(const U32U64& a);
|
U32U64 CountLeadingZeros(const U32U64& a);
|
||||||
|
U32 ExtractRegister(const U32& a, const U32& b, const U8& lsb);
|
||||||
|
U64 ExtractRegister(const U64& a, const U64& b, const U8& lsb);
|
||||||
|
U32U64 ExtractRegister(const U32U64& a, const U32U64& b, const U8& lsb);
|
||||||
|
|
||||||
ResultAndOverflow<U32> SignedSaturatedAdd(const U32& a, const U32& b);
|
ResultAndOverflow<U32> SignedSaturatedAdd(const U32& a, const U32& b);
|
||||||
ResultAndOverflow<U32> SignedSaturatedSub(const U32& a, const U32& b);
|
ResultAndOverflow<U32> SignedSaturatedSub(const U32& a, const U32& b);
|
||||||
|
|
|
@ -122,6 +122,8 @@ OPCODE(ByteReverseHalf, T::U16, T::U16
|
||||||
OPCODE(ByteReverseDual, T::U64, T::U64 )
|
OPCODE(ByteReverseDual, T::U64, T::U64 )
|
||||||
OPCODE(CountLeadingZeros32, T::U32, T::U32 )
|
OPCODE(CountLeadingZeros32, T::U32, T::U32 )
|
||||||
OPCODE(CountLeadingZeros64, T::U64, T::U64 )
|
OPCODE(CountLeadingZeros64, T::U64, T::U64 )
|
||||||
|
OPCODE(ExtractRegister32, T::U32, T::U32, T::U32, T::U8 )
|
||||||
|
OPCODE(ExtractRegister64, T::U64, T::U64, T::U64, T::U8 )
|
||||||
|
|
||||||
// Saturated instructions
|
// Saturated instructions
|
||||||
OPCODE(SignedSaturatedAdd, T::U32, T::U32, T::U32 )
|
OPCODE(SignedSaturatedAdd, T::U32, T::U32, T::U32 )
|
||||||
|
|
Loading…
Reference in a new issue