diff --git a/FEXCore/Source/Interface/Core/Core.cpp b/FEXCore/Source/Interface/Core/Core.cpp index 256a0b13f..29ddbab75 100644 --- a/FEXCore/Source/Interface/Core/Core.cpp +++ b/FEXCore/Source/Interface/Core/Core.cpp @@ -611,7 +611,7 @@ ContextImpl::GenerateIR(FEXCore::Core::InternalThreadState* Thread, uint64_t Gue } else { ForceTSO = IR::ForceTSOMode::ForceDisabled; } - } else if (DecodedInfo->ForceTSO) { + } else if (DecodedInfo->Flags & X86Tables::DecodeFlags::FLAG_FORCE_TSO) { ForceTSO = IR::ForceTSOMode::ForceEnabled; } diff --git a/FEXCore/Source/Interface/Core/Frontend.cpp b/FEXCore/Source/Interface/Core/Frontend.cpp index ac4f236e7..88e8f6cfa 100644 --- a/FEXCore/Source/Interface/Core/Frontend.cpp +++ b/FEXCore/Source/Interface/Core/Frontend.cpp @@ -259,13 +259,13 @@ void Decoder::DecodeModRM_64(X86Tables::DecodedOperand* Operand, X86Tables::ModR if (HasSIB) { FEXCore::X86Tables::SIBDecoded SIB; - if (DecodeInst->DecodedSIB) { + if (DecodeInst->Flags & DecodeFlags::FLAG_DECODED_SIB) { SIB.Hex = DecodeInst->SIB; } else { // Haven't yet grabbed SIB, pull it now DecodeInst->SIB = ReadByte(); SIB.Hex = DecodeInst->SIB; - DecodeInst->DecodedSIB = true; + DecodeInst->Flags |= DecodeFlags::FLAG_DECODED_SIB; } // If the SIB base is 0b101, aka BP or R13 then we have a 32bit displacement @@ -401,9 +401,9 @@ bool Decoder::NormalOp(const FEXCore::X86Tables::X86InstInfo* Info, uint16_t Op, // If we require ModRM and haven't decoded it yet, do it now // Some instructions have to read modrm upfront, others do it later - if (HasMODRM && !DecodeInst->DecodedModRM) { + if (HasMODRM && !(DecodeInst->Flags & DecodeFlags::FLAG_DECODED_MODRM)) { DecodeInst->ModRM = ReadByte(); - DecodeInst->DecodedModRM = true; + DecodeInst->Flags |= DecodeFlags::FLAG_DECODED_MODRM; } // New instruction size decoding @@ -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, @@ -670,7 +679,7 @@ bool Decoder::NormalOpHeader(const FEXCore::X86Tables::X86InstInfo* Info, uint16 } else if (Info->Type >= FEXCore::X86Tables::TYPE_GROUP_1 && Info->Type <= FEXCore::X86Tables::TYPE_GROUP_11) { uint8_t ModRMByte = ReadByte(); DecodeInst->ModRM = ModRMByte; - DecodeInst->DecodedModRM = true; + DecodeInst->Flags |= DecodeFlags::FLAG_DECODED_MODRM; FEXCore::X86Tables::ModRMDecoded ModRM; ModRM.Hex = DecodeInst->ModRM; @@ -687,18 +696,18 @@ bool Decoder::NormalOpHeader(const FEXCore::X86Tables::X86InstInfo* Info, uint16 constexpr uint16_t PF_F2 = 3; uint16_t PrefixType = PF_NONE; - if (DecodeInst->LastEscapePrefix == 0xF3) { + if (LastEscapePrefix == 0xF3) { PrefixType = PF_F3; - } else if (DecodeInst->LastEscapePrefix == 0xF2) { + } else if (LastEscapePrefix == 0xF2) { PrefixType = PF_F2; - } else if (DecodeInst->LastEscapePrefix == 0x66) { + } else if (LastEscapePrefix == 0x66) { PrefixType = PF_66; } // We have ModRM uint8_t ModRMByte = ReadByte(); DecodeInst->ModRM = ModRMByte; - DecodeInst->DecodedModRM = true; + DecodeInst->Flags |= DecodeFlags::FLAG_DECODED_MODRM; FEXCore::X86Tables::ModRMDecoded ModRM; ModRM.Hex = DecodeInst->ModRM; @@ -725,7 +734,7 @@ bool Decoder::NormalOpHeader(const FEXCore::X86Tables::X86InstInfo* Info, uint16 // We have ModRM uint8_t ModRMByte = ReadByte(); DecodeInst->ModRM = ModRMByte; - DecodeInst->DecodedModRM = true; + DecodeInst->Flags |= DecodeFlags::FLAG_DECODED_MODRM; uint16_t X87Op = ((Op - 0xD8) << 8) | ModRMByte; return NormalOp(&(*X87Table)[X87Op], X87Op); @@ -787,7 +796,7 @@ bool Decoder::NormalOpHeader(const FEXCore::X86Tables::X86InstInfo* Info, uint16 // We have ModRM uint8_t ModRMByte = ReadByte(); DecodeInst->ModRM = ModRMByte; - DecodeInst->DecodedModRM = true; + DecodeInst->Flags |= DecodeFlags::FLAG_DECODED_MODRM; FEXCore::X86Tables::ModRMDecoded ModRM; ModRM.Hex = DecodeInst->ModRM; @@ -811,6 +820,7 @@ bool Decoder::NormalOpHeader(const FEXCore::X86Tables::X86InstInfo* Info, uint16 bool Decoder::DecodeInstructionImpl(uint64_t PC) { InstructionSize = 0; + LastEscapePrefix = 0; Instruction.fill(0); DecodeInst = &DecodedBuffer[DecodedSize]; @@ -832,7 +842,7 @@ bool Decoder::DecodeInstructionImpl(uint64_t PC) { // Decode ModRM uint8_t ModRMByte = ReadByte(); DecodeInst->ModRM = ModRMByte; - DecodeInst->DecodedModRM = true; + DecodeInst->Flags |= DecodeFlags::FLAG_DECODED_MODRM; FEXCore::X86Tables::ModRMDecoded ModRM; ModRM.Hex = DecodeInst->ModRM; @@ -871,7 +881,7 @@ bool Decoder::DecodeInstructionImpl(uint64_t PC) { uint16_t LocalOp = (Prefix << 8) | ReadByte(); bool NoOverlay66 = (FEXCore::X86Tables::H0F38TableOps[LocalOp].Flags & InstFlags::FLAGS_NO_OVERLAY66) != 0; - if (DecodeInst->LastEscapePrefix == 0x66 && NoOverlay66) { // Operand Size + if (LastEscapePrefix == 0x66 && NoOverlay66) { // Operand Size // Remove prefix so it doesn't effect calculations. // This is only an escape prefix rather than modifier now DecodeInst->Flags &= ~DecodeFlags::FLAG_OPERAND_SIZE; @@ -887,7 +897,7 @@ bool Decoder::DecodeInstructionImpl(uint64_t PC) { constexpr uint16_t PF_3A_REX = (1 << 1); uint16_t Prefix = PF_3A_NONE; - if (DecodeInst->LastEscapePrefix == 0x66) { // Operand Size + if (LastEscapePrefix == 0x66) { // Operand Size Prefix = PF_3A_66; } @@ -913,17 +923,17 @@ bool Decoder::DecodeInstructionImpl(uint64_t PC) { if (NoOverlay) { // This section of the table ignores prefix extention return NormalOpHeader(&FEXCore::X86Tables::SecondBaseOps[EscapeOp], EscapeOp); - } else if (DecodeInst->LastEscapePrefix == 0xF3) { // REP + } else if (LastEscapePrefix == 0xF3) { // REP // Remove prefix so it doesn't effect calculations. // This is only an escape prefix rather tan modifier now DecodeInst->Flags &= ~DecodeFlags::FLAG_REP_PREFIX; return NormalOpHeader(&FEXCore::X86Tables::RepModOps[EscapeOp], EscapeOp); - } else if (DecodeInst->LastEscapePrefix == 0xF2) { // REPNE + } else if (LastEscapePrefix == 0xF2) { // REPNE // Remove prefix so it doesn't effect calculations. // This is only an escape prefix rather tan modifier now DecodeInst->Flags &= ~DecodeFlags::FLAG_REPNE_PREFIX; return NormalOpHeader(&FEXCore::X86Tables::RepNEModOps[EscapeOp], EscapeOp); - } else if (DecodeInst->LastEscapePrefix == 0x66 && !NoOverlay66) { // Operand Size + } else if (LastEscapePrefix == 0x66 && !NoOverlay66) { // Operand Size // Remove prefix so it doesn't effect calculations. // This is only an escape prefix rather tan modifier now DecodeInst->Flags &= ~DecodeFlags::FLAG_OPERAND_SIZE; @@ -939,7 +949,7 @@ bool Decoder::DecodeInstructionImpl(uint64_t PC) { } case 0x66: // Operand Size prefix DecodeInst->Flags |= DecodeFlags::FLAG_OPERAND_SIZE; - DecodeInst->LastEscapePrefix = Op; + LastEscapePrefix = Op; DecodeFlags::PushOpAddr(&DecodeInst->Flags, DecodeFlags::FLAG_OPERAND_SIZE_LAST); break; case 0x67: // Address Size override prefix @@ -970,11 +980,11 @@ bool Decoder::DecodeInstructionImpl(uint64_t PC) { break; case 0xF2: // REPNE prefix DecodeInst->Flags |= DecodeFlags::FLAG_REPNE_PREFIX; - DecodeInst->LastEscapePrefix = Op; + LastEscapePrefix = Op; break; case 0xF3: // REP prefix DecodeInst->Flags |= DecodeFlags::FLAG_REP_PREFIX; - DecodeInst->LastEscapePrefix = Op; + LastEscapePrefix = Op; break; case 0x64: // FS prefix DecodeInst->Flags = (DecodeInst->Flags & ~FEXCore::X86Tables::DecodeFlags::FLAG_SEGMENTS) | DecodeFlags::FLAG_FS_PREFIX; @@ -1053,10 +1063,10 @@ Decoder::DecodedBlockStatus Decoder::DecodeInstruction(uint64_t PC) { if (DecodeInst->OP == 0x8b && DecodeInst->Src[0].IsGPRIndirect() && IsKnownAtomicDisplacement(DecodeInst->Src[0].Data.GPRIndirect.Displacement)) { - DecodeInst->ForceTSO = true; + DecodeInst->Flags |= X86Tables::DecodeFlags::FLAG_FORCE_TSO; } if (DecodeInst->OP == 0x89 && DecodeInst->Dest.IsGPRIndirect() && IsKnownAtomicDisplacement(DecodeInst->Dest.Data.GPRIndirect.Displacement)) { - DecodeInst->ForceTSO = true; + DecodeInst->Flags |= X86Tables::DecodeFlags::FLAG_FORCE_TSO; } } diff --git a/FEXCore/Source/Interface/Core/Frontend.h b/FEXCore/Source/Interface/Core/Frontend.h index 47cd8f490..bc8386655 100644 --- a/FEXCore/Source/Interface/Core/Frontend.h +++ b/FEXCore/Source/Interface/Core/Frontend.h @@ -125,6 +125,7 @@ private: static constexpr size_t MAX_INST_SIZE = 15; uint8_t InstructionSize {}; std::array Instruction; + uint8_t LastEscapePrefix {}; FEXCore::X86Tables::DecodedInst* DecodeInst; // This is for multiblock data tracking diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp b/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp index 5bc3f887a..12b3c0e72 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 @@ -1336,26 +1336,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) { @@ -2394,7 +2424,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()) { @@ -2895,7 +2925,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); @@ -2910,7 +2940,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); @@ -4441,6 +4471,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); @@ -4562,7 +4606,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 6986fd8fe..5a6ae05b3 100644 --- a/FEXCore/Source/Interface/Core/X86Tables/X86Tables.h +++ b/FEXCore/Source/Interface/Core/X86Tables/X86Tables.h @@ -42,8 +42,9 @@ constexpr uint32_t FLAG_DS_PREFIX = (0b100 << 11); constexpr uint32_t FLAG_FS_PREFIX = (0b101 << 11); constexpr uint32_t FLAG_GS_PREFIX = (0b110 << 11); constexpr uint32_t FLAG_SEGMENTS = (0b111 << 11); -// Bits 14, 15, 16 - Unused - +constexpr uint32_t FLAG_FORCE_TSO = (1 << 14); +constexpr uint32_t FLAG_DECODED_MODRM = (1 << 15); +constexpr uint32_t FLAG_DECODED_SIB = (1 << 16); constexpr uint32_t FLAG_REP_PREFIX = (1 << 17); constexpr uint32_t FLAG_REPNE_PREFIX = (1 << 18); // Size flags @@ -143,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; } @@ -166,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; @@ -193,16 +198,12 @@ struct DecodedInst { X86InstInfo const* TableInfo; uint32_t Flags; - uint8_t OPRaw; uint16_t OP; + uint8_t OPRaw; uint8_t ModRM; uint8_t SIB; uint8_t InstSize; - uint8_t LastEscapePrefix; - bool DecodedModRM; - bool DecodedSIB; - bool ForceTSO; }; union ModRMDecoded {