From 3c639f33b4d56dee3799e7f361facbc2fad2dea4 Mon Sep 17 00:00:00 2001 From: Guillaume Chatelet Date: Mon, 22 Oct 2018 14:46:08 +0000 Subject: [PATCH] [llvm-exegesis] Reject x86 instructions that use non uniform memory accesses Reviewers: courbet Subscribers: tschuett, llvm-commits Differential Revision: https://reviews.llvm.org/D53438 llvm-svn: 344905 --- llvm/tools/llvm-exegesis/lib/X86/Target.cpp | 89 +++++++++++++++++++++-------- 1 file changed, 64 insertions(+), 25 deletions(-) diff --git a/llvm/tools/llvm-exegesis/lib/X86/Target.cpp b/llvm/tools/llvm-exegesis/lib/X86/Target.cpp index 1a7d290..b7548f8 100644 --- a/llvm/tools/llvm-exegesis/lib/X86/Target.cpp +++ b/llvm/tools/llvm-exegesis/lib/X86/Target.cpp @@ -21,12 +21,74 @@ namespace exegesis { 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()); + } + return Result; +} + static llvm::Error IsInvalidOpcode(const Instruction &Instr) { const auto OpcodeName = Instr.Name; if (OpcodeName.startswith("POPF") || OpcodeName.startswith("PUSHF") || 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"); + // 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"); // 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) @@ -281,31 +343,8 @@ class ExegesisX86Target : public ExegesisTarget { unsigned Offset) const override { // FIXME: For instructions that read AND write to memory, we use the same // value for input and output. - for (size_t I = 0, E = IT.Instr.Operands.size(); I < E; ++I) { - const Operand *Op = &IT.Instr.Operands[I]; - if (Op->isExplicit() && Op->isMemory()) { - // Case 1: 5-op memory. - assert((I + 5 <= E) && "x86 memory references are always 5 ops"); - IT.getValueFor(*Op) = llvm::MCOperand::createReg(Reg); // BaseReg - Op = &IT.Instr.Operands[++I]; - assert(Op->isMemory()); - assert(Op->isExplicit()); - IT.getValueFor(*Op) = llvm::MCOperand::createImm(1); // ScaleAmt - Op = &IT.Instr.Operands[++I]; - assert(Op->isMemory()); - assert(Op->isExplicit()); - IT.getValueFor(*Op) = llvm::MCOperand::createReg(0); // IndexReg - Op = &IT.Instr.Operands[++I]; - assert(Op->isMemory()); - assert(Op->isExplicit()); - IT.getValueFor(*Op) = llvm::MCOperand::createImm(Offset); // Disp - Op = &IT.Instr.Operands[++I]; - assert(Op->isMemory()); - assert(Op->isExplicit()); - IT.getValueFor(*Op) = llvm::MCOperand::createReg(0); // Segment - // Case2: segment:index addressing. We assume that ES is 0. - } - } + for (auto &MemoryRange : getMemoryOperandRanges(IT.Instr.Operands)) + MemoryRange.fillOrDie(IT, Reg, Offset); } std::vector setRegTo(const llvm::MCSubtargetInfo &STI, -- 2.7.4