diff --git a/FEXCore/Source/Interface/Core/Frontend.cpp b/FEXCore/Source/Interface/Core/Frontend.cpp index 996c57bca..88e8f6cfa 100644 --- a/FEXCore/Source/Interface/Core/Frontend.cpp +++ b/FEXCore/Source/Interface/Core/Frontend.cpp @@ -634,11 +634,20 @@ bool Decoder::NormalOp(const FEXCore::X86Tables::X86InstInfo* Info, uint16_t Op, Literal = static_cast(Literal); } DecodeInst->Src[CurrentSrc].Data.Literal.Size = DestSize; + DecodeInst->Src[CurrentSrc].Data.Literal.SignExtend = true; + } + + DecodeInst->Src[CurrentSrc].Type = DecodedOperand::OpType::Literal; + DecodeInst->Src[CurrentSrc].Data.Literal.Value = Literal; + ++CurrentSrc; + + if (Bytes == 8) [[unlikely]] { + DecodeInst->Src[CurrentSrc].Data.Literal.Size = 4; + DecodeInst->Src[CurrentSrc].Type = DecodedOperand::OpType::Literal; + DecodeInst->Src[CurrentSrc].Data.Literal.Value = Literal >> 32; } Bytes = 0; - DecodeInst->Src[CurrentSrc].Type = DecodedOperand::OpType::Literal; - DecodeInst->Src[CurrentSrc].Data.Literal.Value = Literal; } LOGMAN_THROW_A_FMT(Bytes == 0, "Inst at 0x{:x}: 0x{:04x} '{}' Had an instruction of size {} with {} remaining", DecodeInst->PC, diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp b/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp index a49eb286f..702d8db29 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp @@ -789,7 +789,7 @@ void OpDispatchBuilder::CondJUMPRCXOp(OpcodeArgs) { StartNewBlock(); // Store the new RIP - ExitRelocatedPC(Op, Op->Src[0].Data.Literal.Value); + ExitRelocatedPC(Op, Op->Src[0].Literal()); } // Failure to take branch @@ -858,7 +858,7 @@ void OpDispatchBuilder::LoopOp(OpcodeArgs) { StartNewBlock(); // Store the new RIP - ExitRelocatedPC(Op, Op->Src[1].Data.Literal.Value); + ExitRelocatedPC(Op, Op->Src[1].Literal()); } // Failure to take branch @@ -1342,26 +1342,56 @@ void OpDispatchBuilder::MOVSegOp(OpcodeArgs, bool ToSeg) { } void OpDispatchBuilder::MOVOffsetOp(OpcodeArgs) { - Ref Src; + auto GenMemSrcFromOp = [&](size_t StartingSource) -> AddressMode { + const uint64_t Lower = Op->Src[StartingSource].Literal(); + const uint64_t Upper = Op->Src[StartingSource + 1].Literal(); + const uint64_t Combined = (Upper << 32) | Lower; + const auto GPRSize = GetGPROpSize(); + + AddressMode A { + .Segment = GetSegment(Op->Flags), + .Offset = static_cast(Combined), + .AddrSize = (Op->Flags & X86Tables::DecodeFlags::FLAG_ADDRESS_SIZE) != 0 ? (GPRSize >> 1) : GPRSize, + .NonTSO = false, + }; + + return A; + }; switch (Op->OP) { case 0xA0: - case 0xA1: + case 0xA1: { // Source is memory(literal) // Dest is GPR - Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, {.ForceLoad = true}); + Ref Src {}; + if (Op->Src[0].Data.Literal.Size <= 4) { + Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, {.ForceLoad = true}); + } else { + const auto OpSize = OpSizeFromSrc(Op); + auto A = GenMemSrcFromOp(0); + Src = _LoadMemAutoTSO(GPRClass, OpSize, A, OpSize::i8Bit); + } StoreResult(GPRClass, Op, Op->Dest, Src, OpSize::iInvalid); break; + } case 0xA2: - case 0xA3: + case 0xA3: { // Source is GPR // Dest is memory(literal) - Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, {.AllowUpperGarbage = true}); + Ref Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, {.AllowUpperGarbage = true}); + // This one is a bit special since the destination is a literal // So the destination gets stored in Src[1] - StoreResult(GPRClass, Op, Op->Src[1], Src, OpSize::iInvalid); + if (Op->Src[1].Data.Literal.Size <= 4) { + StoreResult(GPRClass, Op, Op->Src[1], Src, OpSize::iInvalid); + } else { + const auto OpSize = OpSizeFromSrc(Op); + auto A = GenMemSrcFromOp(1); + _StoreMemAutoTSO(GPRClass, OpSize, A, Src, OpSize::i8Bit); + } break; } + } } void OpDispatchBuilder::CPUIDOp(OpcodeArgs) { @@ -2400,7 +2430,7 @@ void OpDispatchBuilder::BTOp(OpcodeArgs, uint32_t SrcIndex, BTAction Action) { } else { // Can only be an immediate // Masked by operand size - Src = ARef(Op->Src[SrcIndex].Data.Literal.Value & Mask); + Src = ARef(Op->Src[SrcIndex].Literal() & Mask); } if (Op->Dest.IsGPR()) { @@ -2901,7 +2931,7 @@ void OpDispatchBuilder::AASOp(OpcodeArgs) { void OpDispatchBuilder::AAMOp(OpcodeArgs) { auto AL = LoadGPRRegister(X86State::REG_RAX, OpSize::i8Bit); - auto Imm8 = Constant(Op->Src[0].Data.Literal.Value & 0xFF); + auto Imm8 = Constant(Op->Src[0].Literal() & 0xFF); Ref Quotient = _AllocateGPR(true); Ref Remainder = _AllocateGPR(true); _UDiv(OpSize::i64Bit, AL, Invalid(), Imm8, Quotient, Remainder); @@ -2916,7 +2946,7 @@ void OpDispatchBuilder::AAMOp(OpcodeArgs) { void OpDispatchBuilder::AADOp(OpcodeArgs) { auto A = LoadGPRRegister(X86State::REG_RAX); auto AH = _Lshr(OpSize::i32Bit, A, Constant(8)); - auto Imm8 = Constant(Op->Src[0].Data.Literal.Value & 0xFF); + auto Imm8 = Constant(Op->Src[0].Literal() & 0xFF); auto NewAL = Add(OpSize::i64Bit, A, _Mul(OpSize::i64Bit, AH, Imm8)); auto Result = _And(OpSize::i64Bit, NewAL, Constant(0xFF)); StoreGPRRegister(X86State::REG_RAX, Result, OpSize::i16Bit); @@ -4447,6 +4477,20 @@ void OpDispatchBuilder::MOVGPROp(OpcodeArgs, uint32_t SrcIndex) { StoreResult(GPRClass, Op, Src, OpSize::i8Bit); } +void OpDispatchBuilder::MOVGPRImmediate(OpcodeArgs) { + Ref Src {}; + if (Op->Src[0].Data.Literal.Size <= 4) { + Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, {.Align = OpSize::i8Bit, .AllowUpperGarbage = true}); + } else { + // 8-byte literal is special cased. + const uint64_t Lower = Op->Src[0].Literal(); + const uint64_t Upper = Op->Src[1].Literal(); + const uint64_t Combined = (Upper << 32) | Lower; + Src = _Constant(Combined); + } + StoreResult(GPRClass, Op, Src, OpSize::i8Bit); +} + void OpDispatchBuilder::MOVGPRNTOp(OpcodeArgs) { Ref Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, {.Align = OpSize::i8Bit}); StoreResult(GPRClass, Op, Src, OpSize::i8Bit, MemoryAccessType::STREAM); @@ -4568,7 +4612,7 @@ void OpDispatchBuilder::INTOp(OpcodeArgs) { switch (Op->OP) { case 0xCD: { // INT imm8 - uint8_t Literal = Op->Src[0].Data.Literal.Value; + uint8_t Literal = Op->Src[0].Literal(); #ifndef _WIN32 constexpr uint8_t SYSCALL_LITERAL = 0x80; diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher.h b/FEXCore/Source/Interface/Core/OpcodeDispatcher.h index 732759865..1d229e25b 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher.h +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher.h @@ -318,6 +318,7 @@ public: void UnhandledOp(OpcodeArgs); void MOVGPROp(OpcodeArgs, uint32_t SrcIndex); + void MOVGPRImmediate(OpcodeArgs); void MOVGPRNTOp(OpcodeArgs); void MOVVectorAlignedOp(OpcodeArgs); void MOVVectorUnalignedOp(OpcodeArgs); diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher/BaseTables.h b/FEXCore/Source/Interface/Core/OpcodeDispatcher/BaseTables.h index 7841ed2fb..9b86097ba 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher/BaseTables.h +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher/BaseTables.h @@ -53,7 +53,7 @@ constexpr inline DispatchTableEntry OpDispatch_BaseOpTable[] = { {0xAA, 2, &OpDispatchBuilder::STOSOp}, {0xAC, 2, &OpDispatchBuilder::LODSOp}, {0xAE, 2, &OpDispatchBuilder::SCASOp}, - {0xB0, 16, &OpDispatchBuilder::Bind<&OpDispatchBuilder::MOVGPROp, 0>}, + {0xB0, 16, &OpDispatchBuilder::Bind<&OpDispatchBuilder::MOVGPRImmediate>}, {0xC2, 2, &OpDispatchBuilder::RETOp}, {0xC8, 1, &OpDispatchBuilder::EnterOp}, {0xC9, 1, &OpDispatchBuilder::LEAVEOp}, diff --git a/FEXCore/Source/Interface/Core/X86Tables/X86Tables.h b/FEXCore/Source/Interface/Core/X86Tables/X86Tables.h index bac0c5fb2..5a6ae05b3 100644 --- a/FEXCore/Source/Interface/Core/X86Tables/X86Tables.h +++ b/FEXCore/Source/Interface/Core/X86Tables/X86Tables.h @@ -144,6 +144,9 @@ struct DecodedOperand { } uint64_t Literal() const { LOGMAN_THROW_A_FMT(IsLiteral(), "Precondition: must be a literal"); + if (Data.Literal.SignExtend) { + return static_cast(static_cast(Data.Literal.Value)); + } return Data.Literal.Value; } @@ -167,8 +170,9 @@ struct DecodedOperand { } RIPLiteral; struct LiteralType { - uint64_t Value; - uint8_t Size; + uint32_t Value; + uint8_t Size : 7 ; + bool SignExtend : 1; auto operator<=>(const LiteralType&) const = default; } Literal;