Index: llvm/trunk/test/tools/llvm-exegesis/X86/uops-ADD32mi8.s =================================================================== --- llvm/trunk/test/tools/llvm-exegesis/X86/uops-ADD32mi8.s +++ llvm/trunk/test/tools/llvm-exegesis/X86/uops-ADD32mi8.s @@ -0,0 +1,6 @@ +# RUN: llvm-exegesis -mode=uops -opcode-name=ADD32mi8 | FileCheck %s + +CHECK: mode: uops +CHECK-NEXT: key: +CHECK-NEXT: instructions: +CHECK-NEXT: ADD32mi8 Index: llvm/trunk/test/tools/llvm-exegesis/X86/uops-ADD32mr.s =================================================================== --- llvm/trunk/test/tools/llvm-exegesis/X86/uops-ADD32mr.s +++ llvm/trunk/test/tools/llvm-exegesis/X86/uops-ADD32mr.s @@ -0,0 +1,6 @@ +# RUN: llvm-exegesis -mode=uops -opcode-name=ADD32mr | FileCheck %s + +CHECK: mode: uops +CHECK-NEXT: key: +CHECK-NEXT: instructions: +CHECK-NEXT: ADD32mr Index: llvm/trunk/test/tools/llvm-exegesis/X86/uops-ADD32rm.s =================================================================== --- llvm/trunk/test/tools/llvm-exegesis/X86/uops-ADD32rm.s +++ llvm/trunk/test/tools/llvm-exegesis/X86/uops-ADD32rm.s @@ -0,0 +1,6 @@ +# RUN: llvm-exegesis -mode=uops -opcode-name=ADD32rm | FileCheck %s + +CHECK: mode: uops +CHECK-NEXT: key: +CHECK-NEXT: instructions: +CHECK-NEXT: ADD32rm Index: llvm/trunk/test/tools/llvm-exegesis/X86/uops-BEXTR32rm.s =================================================================== --- llvm/trunk/test/tools/llvm-exegesis/X86/uops-BEXTR32rm.s +++ llvm/trunk/test/tools/llvm-exegesis/X86/uops-BEXTR32rm.s @@ -0,0 +1,6 @@ +# RUN: llvm-exegesis -mode=uops -opcode-name=BEXTR32rm | FileCheck %s + +CHECK: mode: uops +CHECK-NEXT: key: +CHECK-NEXT: instructions: +CHECK-NEXT: BEXTR32rm Index: llvm/trunk/test/tools/llvm-exegesis/X86/uops-BSF16rm.s =================================================================== --- llvm/trunk/test/tools/llvm-exegesis/X86/uops-BSF16rm.s +++ llvm/trunk/test/tools/llvm-exegesis/X86/uops-BSF16rm.s @@ -0,0 +1,6 @@ +# RUN: llvm-exegesis -mode=uops -opcode-name=BSF16rm | FileCheck %s + +CHECK: mode: uops +CHECK-NEXT: key: +CHECK-NEXT: instructions: +CHECK-NEXT: BSF16rm Index: llvm/trunk/test/tools/llvm-exegesis/X86/uops-BTR64mr.s =================================================================== --- llvm/trunk/test/tools/llvm-exegesis/X86/uops-BTR64mr.s +++ llvm/trunk/test/tools/llvm-exegesis/X86/uops-BTR64mr.s @@ -0,0 +1,6 @@ +# RUN: llvm-exegesis -mode=uops -opcode-name=BTR64mr | FileCheck %s + +CHECK: mode: uops +CHECK-NEXT: key: +CHECK-NEXT: instructions: +CHECK-NEXT: BTR64mr Index: llvm/trunk/test/tools/llvm-exegesis/X86/uops-VFMADDSS4rm.s =================================================================== --- llvm/trunk/test/tools/llvm-exegesis/X86/uops-VFMADDSS4rm.s +++ llvm/trunk/test/tools/llvm-exegesis/X86/uops-VFMADDSS4rm.s @@ -0,0 +1,6 @@ +# RUN: llvm-exegesis -mode=uops -opcode-name=VFMADDSS4rm | FileCheck %s + +CHECK: mode: uops +CHECK-NEXT: key: +CHECK-NEXT: instructions: +CHECK-NEXT: VFMADDSS4rm Index: llvm/trunk/tools/llvm-exegesis/lib/X86/Target.cpp =================================================================== --- llvm/trunk/tools/llvm-exegesis/lib/X86/Target.cpp +++ llvm/trunk/tools/llvm-exegesis/lib/X86/Target.cpp @@ -22,55 +22,124 @@ namespace { -// A chunk of instruction's operands that represents a single memory access. -struct MemoryOperandRange { - MemoryOperandRange(llvm::ArrayRef Operands) : Ops(Operands) {} - - // Setup InstructionTemplate so the memory access represented by this object - // points to [reg] + offset. - void fillOrDie(InstructionTemplate &IT, unsigned Reg, unsigned Offset) { - switch (Ops.size()) { - case 5: - IT.getValueFor(Ops[0]) = llvm::MCOperand::createReg(Reg); // BaseReg - IT.getValueFor(Ops[1]) = llvm::MCOperand::createImm(1); // ScaleAmt - IT.getValueFor(Ops[2]) = llvm::MCOperand::createReg(0); // IndexReg - IT.getValueFor(Ops[3]) = llvm::MCOperand::createImm(Offset); // Disp - IT.getValueFor(Ops[4]) = llvm::MCOperand::createReg(0); // Segment - break; - default: - llvm::errs() << Ops.size() << "-op are not handled right now (" - << IT.Instr.Name << ")\n"; - llvm_unreachable("Invalid memory configuration"); - } - } - - // Returns whether Range can be filled. - static bool isValid(const MemoryOperandRange &Range) { - return Range.Ops.size() == 5; - } - - // Returns whether Op is a valid memory operand. - static bool isMemoryOperand(const Operand &Op) { - return Op.isMemory() && Op.isExplicit(); - } - - llvm::ArrayRef Ops; -}; - -// X86 memory access involve non constant number of operands, this function -// extracts contiguous memory operands into MemoryOperandRange so it's easier to -// check and fill. -static std::vector -getMemoryOperandRanges(llvm::ArrayRef Operands) { - std::vector Result; - while (!Operands.empty()) { - Operands = Operands.drop_until(MemoryOperandRange::isMemoryOperand); - auto MemoryOps = Operands.take_while(MemoryOperandRange::isMemoryOperand); - if (!MemoryOps.empty()) - Result.push_back(MemoryOps); - Operands = Operands.drop_front(MemoryOps.size()); +// Returns an error if we cannot handle the memory references in this +// instruction. +Error isInvalidMemoryInstr(const Instruction &Instr) { + switch (Instr.Description->TSFlags & X86II::FormMask) { + default: + llvm_unreachable("Unknown FormMask value"); + // These have no memory access. + case X86II::Pseudo: + case X86II::RawFrm: + case X86II::MRMDestReg: + case X86II::MRMSrcReg: + case X86II::MRMSrcReg4VOp3: + case X86II::MRMSrcRegOp4: + case X86II::MRMXr: + case X86II::MRM0r: + case X86II::MRM1r: + case X86II::MRM2r: + case X86II::MRM3r: + case X86II::MRM4r: + case X86II::MRM5r: + case X86II::MRM6r: + case X86II::MRM7r: + case X86II::MRM_C0: + case X86II::MRM_C1: + case X86II::MRM_C2: + case X86II::MRM_C3: + case X86II::MRM_C4: + case X86II::MRM_C5: + case X86II::MRM_C6: + case X86II::MRM_C7: + case X86II::MRM_C8: + case X86II::MRM_C9: + case X86II::MRM_CA: + case X86II::MRM_CB: + case X86II::MRM_CC: + case X86II::MRM_CD: + case X86II::MRM_CE: + case X86II::MRM_CF: + case X86II::MRM_D0: + case X86II::MRM_D1: + case X86II::MRM_D2: + case X86II::MRM_D3: + case X86II::MRM_D4: + case X86II::MRM_D5: + case X86II::MRM_D6: + case X86II::MRM_D7: + case X86II::MRM_D8: + case X86II::MRM_D9: + case X86II::MRM_DA: + case X86II::MRM_DB: + case X86II::MRM_DC: + case X86II::MRM_DD: + case X86II::MRM_DE: + case X86II::MRM_DF: + case X86II::MRM_E0: + case X86II::MRM_E1: + case X86II::MRM_E2: + case X86II::MRM_E3: + case X86II::MRM_E4: + case X86II::MRM_E5: + case X86II::MRM_E6: + case X86II::MRM_E7: + case X86II::MRM_E8: + case X86II::MRM_E9: + case X86II::MRM_EA: + case X86II::MRM_EB: + case X86II::MRM_EC: + case X86II::MRM_ED: + case X86II::MRM_EE: + case X86II::MRM_EF: + case X86II::MRM_F0: + case X86II::MRM_F1: + case X86II::MRM_F2: + case X86II::MRM_F3: + case X86II::MRM_F4: + case X86II::MRM_F5: + case X86II::MRM_F6: + case X86II::MRM_F7: + case X86II::MRM_F8: + case X86II::MRM_F9: + case X86II::MRM_FA: + case X86II::MRM_FB: + case X86II::MRM_FC: + case X86II::MRM_FD: + case X86II::MRM_FE: + case X86II::MRM_FF: + case X86II::RawFrmImm8: + return Error::success(); + case X86II::AddRegFrm: + return (Instr.Description->Opcode == X86::POP16r || Instr.Description->Opcode == X86::POP32r || + Instr.Description->Opcode == X86::PUSH16r || Instr.Description->Opcode == X86::PUSH32r) + ? make_error( + "unsupported opcode: unsupported memory access") + : Error::success(); + // These access memory and are handled. + case X86II::MRMDestMem: + case X86II::MRMSrcMem: + case X86II::MRMSrcMem4VOp3: + case X86II::MRMSrcMemOp4: + case X86II::MRMXm: + case X86II::MRM0m: + case X86II::MRM1m: + case X86II::MRM2m: + case X86II::MRM3m: + case X86II::MRM4m: + case X86II::MRM5m: + case X86II::MRM6m: + case X86II::MRM7m: + return Error::success(); + // These access memory and are not handled yet. + case X86II::RawFrmImm16: + case X86II::RawFrmMemOffs: + case X86II::RawFrmSrc: + case X86II::RawFrmDst: + case X86II::RawFrmDstSrc: + return make_error( + "unsupported opcode: non uniform memory access"); } - return Result; } static llvm::Error IsInvalidOpcode(const Instruction &Instr) { @@ -82,23 +151,14 @@ OpcodeName.startswith("ADJCALLSTACK")) return llvm::make_error( "unsupported opcode: Push/Pop/AdjCallStack"); - const bool ValidMemoryOperands = llvm::all_of( - getMemoryOperandRanges(Instr.Operands), MemoryOperandRange::isValid); - if (!ValidMemoryOperands) - return llvm::make_error( - "unsupported opcode: non uniform memory access"); + if (llvm::Error Error = isInvalidMemoryInstr(Instr)) + return std::move(Error); // We do not handle instructions with OPERAND_PCREL. for (const Operand &Op : Instr.Operands) if (Op.isExplicit() && Op.getExplicitOperandInfo().OperandType == llvm::MCOI::OPERAND_PCREL) return llvm::make_error( "unsupported opcode: PC relative operand"); - for (const Operand &Op : Instr.Operands) - if (Op.isReg() && Op.isExplicit() && - Op.getExplicitOperandInfo().RegClass == - llvm::X86::SEGMENT_REGRegClassID) - return llvm::make_error( - "unsupported opcode: access segment memory"); // We do not handle second-form X87 instructions. We only handle first-form // ones (_Fp), see comment in X86InstrFPStack.td. for (const Operand &Op : Instr.Operands) @@ -357,10 +417,28 @@ void fillMemoryOperands(InstructionTemplate &IT, unsigned Reg, unsigned Offset) const override { - // FIXME: For instructions that read AND write to memory, we use the same - // value for input and output. - for (auto &MemoryRange : getMemoryOperandRanges(IT.Instr.Operands)) - MemoryRange.fillOrDie(IT, Reg, Offset); + assert(!isInvalidMemoryInstr(IT.Instr) && + "fillMemoryOperands requires a valid memory instruction"); + int MemOpIdx = X86II::getMemoryOperandNo(IT.Instr.Description->TSFlags); + assert(MemOpIdx >= 0 && "invalid memory operand index"); + // getMemoryOperandNo() ignores tied operands, so we have to add them back. + for (unsigned I = 0; I <= static_cast(MemOpIdx); ++I) { + const auto &Op = IT.Instr.Operands[I]; + if (Op.isTied() && Op.getTiedToIndex() < I) { + ++MemOpIdx; + } + } + // Now fill in the memory operands. + const auto SetOp = [&IT](int OpIdx, const MCOperand &OpVal) { + const auto Op = IT.Instr.Operands[OpIdx]; + assert(Op.isMemory() && Op.isExplicit() && "invalid memory pattern"); + IT.getValueFor(Op) = OpVal; + }; + SetOp(MemOpIdx + 0, MCOperand::createReg(Reg)); // BaseReg + SetOp(MemOpIdx + 1, MCOperand::createImm(1)); // ScaleAmt + SetOp(MemOpIdx + 2, MCOperand::createReg(0)); // IndexReg + SetOp(MemOpIdx + 3, MCOperand::createImm(Offset)); // Disp + SetOp(MemOpIdx + 4, MCOperand::createReg(0)); // Segment } std::vector setRegTo(const llvm::MCSubtargetInfo &STI,