mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-02-01 05:01:59 +01:00
[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
This commit is contained in:
parent
940854b6ef
commit
dc38d0d574
@ -21,12 +21,74 @@ namespace exegesis {
|
||||
|
||||
namespace {
|
||||
|
||||
// A chunk of instruction's operands that represents a single memory access.
|
||||
struct MemoryOperandRange {
|
||||
MemoryOperandRange(llvm::ArrayRef<Operand> 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<Operand> 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<MemoryOperandRange>
|
||||
getMemoryOperandRanges(llvm::ArrayRef<Operand> Operands) {
|
||||
std::vector<MemoryOperandRange> 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<BenchmarkFailure>(
|
||||
"unsupported opcode: Push/Pop/AdjCallStack");
|
||||
const bool ValidMemoryOperands = llvm::all_of(
|
||||
getMemoryOperandRanges(Instr.Operands), MemoryOperandRange::isValid);
|
||||
if (!ValidMemoryOperands)
|
||||
return llvm::make_error<BenchmarkFailure>(
|
||||
"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<BenchmarkFailure>(
|
||||
"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<llvm::MCInst> setRegTo(const llvm::MCSubtargetInfo &STI,
|
||||
|
Loading…
x
Reference in New Issue
Block a user