[llvm] r346330 - [llvm-exegesis] Correclty handle all X86 memory encoding formats.
Clement Courbet via llvm-commits
llvm-commits at lists.llvm.org
Wed Nov 7 08:14:56 PST 2018
Author: courbet
Date: Wed Nov 7 08:14:55 2018
New Revision: 346330
URL: http://llvm.org/viewvc/llvm-project?rev=346330&view=rev
Log:
[llvm-exegesis] Correclty handle all X86 memory encoding formats.
Summary:
Add unit tests to check the support for each supported format to avoid
regressions such as the one in PR36906.
Reviewers: gchatelet
Subscribers: tschuett, lebedev.ri, llvm-commits
Differential Revision: https://reviews.llvm.org/D54144
Added:
llvm/trunk/test/tools/llvm-exegesis/X86/uops-ADD32mi8.s
llvm/trunk/test/tools/llvm-exegesis/X86/uops-ADD32mr.s
llvm/trunk/test/tools/llvm-exegesis/X86/uops-ADD32rm.s
llvm/trunk/test/tools/llvm-exegesis/X86/uops-BEXTR32rm.s
llvm/trunk/test/tools/llvm-exegesis/X86/uops-BSF16rm.s
llvm/trunk/test/tools/llvm-exegesis/X86/uops-BTR64mr.s
llvm/trunk/test/tools/llvm-exegesis/X86/uops-VFMADDSS4rm.s
Modified:
llvm/trunk/tools/llvm-exegesis/lib/X86/Target.cpp
Added: llvm/trunk/test/tools/llvm-exegesis/X86/uops-ADD32mi8.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-exegesis/X86/uops-ADD32mi8.s?rev=346330&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-exegesis/X86/uops-ADD32mi8.s (added)
+++ llvm/trunk/test/tools/llvm-exegesis/X86/uops-ADD32mi8.s Wed Nov 7 08:14:55 2018
@@ -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
Added: llvm/trunk/test/tools/llvm-exegesis/X86/uops-ADD32mr.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-exegesis/X86/uops-ADD32mr.s?rev=346330&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-exegesis/X86/uops-ADD32mr.s (added)
+++ llvm/trunk/test/tools/llvm-exegesis/X86/uops-ADD32mr.s Wed Nov 7 08:14:55 2018
@@ -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
Added: llvm/trunk/test/tools/llvm-exegesis/X86/uops-ADD32rm.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-exegesis/X86/uops-ADD32rm.s?rev=346330&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-exegesis/X86/uops-ADD32rm.s (added)
+++ llvm/trunk/test/tools/llvm-exegesis/X86/uops-ADD32rm.s Wed Nov 7 08:14:55 2018
@@ -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
Added: llvm/trunk/test/tools/llvm-exegesis/X86/uops-BEXTR32rm.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-exegesis/X86/uops-BEXTR32rm.s?rev=346330&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-exegesis/X86/uops-BEXTR32rm.s (added)
+++ llvm/trunk/test/tools/llvm-exegesis/X86/uops-BEXTR32rm.s Wed Nov 7 08:14:55 2018
@@ -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
Added: llvm/trunk/test/tools/llvm-exegesis/X86/uops-BSF16rm.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-exegesis/X86/uops-BSF16rm.s?rev=346330&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-exegesis/X86/uops-BSF16rm.s (added)
+++ llvm/trunk/test/tools/llvm-exegesis/X86/uops-BSF16rm.s Wed Nov 7 08:14:55 2018
@@ -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
Added: llvm/trunk/test/tools/llvm-exegesis/X86/uops-BTR64mr.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-exegesis/X86/uops-BTR64mr.s?rev=346330&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-exegesis/X86/uops-BTR64mr.s (added)
+++ llvm/trunk/test/tools/llvm-exegesis/X86/uops-BTR64mr.s Wed Nov 7 08:14:55 2018
@@ -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
Added: llvm/trunk/test/tools/llvm-exegesis/X86/uops-VFMADDSS4rm.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-exegesis/X86/uops-VFMADDSS4rm.s?rev=346330&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-exegesis/X86/uops-VFMADDSS4rm.s (added)
+++ llvm/trunk/test/tools/llvm-exegesis/X86/uops-VFMADDSS4rm.s Wed Nov 7 08:14:55 2018
@@ -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
Modified: llvm/trunk/tools/llvm-exegesis/lib/X86/Target.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/X86/Target.cpp?rev=346330&r1=346329&r2=346330&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/X86/Target.cpp (original)
+++ llvm/trunk/tools/llvm-exegesis/lib/X86/Target.cpp Wed Nov 7 08:14:55 2018
@@ -22,55 +22,124 @@ 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());
+// 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<BenchmarkFailure>(
+ "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<BenchmarkFailure>(
+ "unsupported opcode: non uniform memory access");
}
- return Result;
}
static llvm::Error IsInvalidOpcode(const Instruction &Instr) {
@@ -82,23 +151,14 @@ static llvm::Error IsInvalidOpcode(const
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");
+ 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<BenchmarkFailure>(
"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<BenchmarkFailure>(
- "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 @@ private:
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<unsigned>(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<llvm::MCInst> setRegTo(const llvm::MCSubtargetInfo &STI,
More information about the llvm-commits
mailing list