Unverified Commit 6030fe01 authored by Roman Lebedev's avatar Roman Lebedev
Browse files

[llvm-exegesis] Exploring X86::OperandType::OPERAND_COND_CODE

Summary:
Currently, we only have nice exploration for LEA instruction,
while for the rest, we rely on `randomizeUnsetVariables()`
to sometimes generate something interesting.
While that works, it isn't very reliable in coverage :)

Here, i'm making an assumption that while we may want to explore
multi-instruction configs, we are most interested in the
characteristics of the main instruction we were asked about.

Which we can do, by taking the existing `randomizeMCOperand()`,
and turning it on it's head - instead of relying on it to randomly fill
one of the interesting values, let's pregenerate all the possible interesting
values for the variable, and then generate as much `InstructionTemplate`
combinations of these possible values for variables as needed/possible.

Of course, that requires invasive changes to no longer pass just the
naked `Instruction`, but sometimes partially filled `InstructionTemplate`.

As it can be seen from the test, this allows us to explore
`X86::OperandType::OPERAND_COND_CODE` for instructions
that take such an operand.
I'm hoping this will greatly simplify exploration.

Reviewers: courbet, gchatelet

Reviewed By: gchatelet

Subscribers: orodley, mgorny, sdardis, tschuett, jrtc27, atanasyan, mstojanovic, andreadb, RKSimon, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D74156
parent 38333164
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
# RUN: llvm-exegesis -mode=latency -opcode-name=SETCCr --max-configs-per-opcode=1 | FileCheck %s --check-prefix=CHECK
# RUN: llvm-exegesis -mode=latency -opcode-name=SETCCr --max-configs-per-opcode=256 | FileCheck %s --check-prefix=SWEEP

CHECK:      ---
CHECK-NEXT: mode: latency
CHECK-NEXT: key:
CHECK-NEXT:   instructions:
CHECK-NEXT:     'SETCCr {{.*}} i_0x{{[0-9a-f]}}'

SWEEP-DAG:      'SETCCr {{.*}} i_0x0'
SWEEP-DAG:      'SETCCr {{.*}} i_0x1'
SWEEP-DAG:      'SETCCr {{.*}} i_0x2'
SWEEP-DAG:      'SETCCr {{.*}} i_0x3'
SWEEP-DAG:      'SETCCr {{.*}} i_0x4'
SWEEP-DAG:      'SETCCr {{.*}} i_0x5'
SWEEP-DAG:      'SETCCr {{.*}} i_0x6'
SWEEP-DAG:      'SETCCr {{.*}} i_0x7'
SWEEP-DAG:      'SETCCr {{.*}} i_0x8'
SWEEP-DAG:      'SETCCr {{.*}} i_0x9'
SWEEP-DAG:      'SETCCr {{.*}} i_0xa'
SWEEP-DAG:      'SETCCr {{.*}} i_0xb'
SWEEP-DAG:      'SETCCr {{.*}} i_0xc'
SWEEP-DAG:      'SETCCr {{.*}} i_0xd'
SWEEP-DAG:      'SETCCr {{.*}} i_0xe'
SWEEP-DAG:      'SETCCr {{.*}} i_0xf'
+5 −0
Original line number Diff line number Diff line
@@ -38,6 +38,11 @@ struct InstructionTemplate {
  bool hasImmediateVariables() const;
  const Instruction &getInstr() const { return *Instr; }
  ArrayRef<MCOperand> getVariableValues() const { return VariableValues; }
  void setVariableValues(ArrayRef<MCOperand> NewVariableValues) {
    assert(VariableValues.size() == NewVariableValues.size() &&
           "Value count mismatch");
    VariableValues.assign(NewVariableValues.begin(), NewVariableValues.end());
  }

  // Builds an MCInst from this InstructionTemplate setting its operands
  // to the corresponding variable values. Precondition: All VariableValues must
+10 −9
Original line number Diff line number Diff line
@@ -154,8 +154,10 @@ static std::vector<InstructionTemplate> generateSnippetUsingStaticRenaming(
  }
}

Expected<std::vector<CodeTemplate>> ParallelSnippetGenerator::generateCodeTemplates(
    const Instruction &Instr, const BitVector &ForbiddenRegisters) const {
Expected<std::vector<CodeTemplate>>
ParallelSnippetGenerator::generateCodeTemplates(
    InstructionTemplate Variant, const BitVector &ForbiddenRegisters) const {
  const Instruction &Instr = Variant.getInstr();
  CodeTemplate CT;
  CT.ScratchSpacePointerInReg =
      Instr.hasMemoryOperands()
@@ -163,16 +165,15 @@ Expected<std::vector<CodeTemplate>> ParallelSnippetGenerator::generateCodeTempla
                State.getTargetMachine().getTargetTriple())
          : 0;
  const AliasingConfigurations SelfAliasing(Instr, Instr);
  InstructionTemplate IT(&Instr);
  if (SelfAliasing.empty()) {
    CT.Info = "instruction is parallel, repeating a random one.";
    CT.Instructions.push_back(std::move(IT));
    CT.Instructions.push_back(std::move(Variant));
    instantiateMemoryOperands(CT.ScratchSpacePointerInReg, CT.Instructions);
    return getSingleton(std::move(CT));
  }
  if (SelfAliasing.hasImplicitAliasing()) {
    CT.Info = "instruction is serial, repeating a random one.";
    CT.Instructions.push_back(std::move(IT));
    CT.Instructions.push_back(std::move(Variant));
    instantiateMemoryOperands(CT.ScratchSpacePointerInReg, CT.Instructions);
    return getSingleton(std::move(CT));
  }
@@ -180,7 +181,7 @@ Expected<std::vector<CodeTemplate>> ParallelSnippetGenerator::generateCodeTempla
  if (!TiedVariables.empty()) {
    CT.Info = "instruction has tied variables, using static renaming.";
    CT.Instructions = generateSnippetUsingStaticRenaming(
        State, IT, TiedVariables, ForbiddenRegisters);
        State, Variant, TiedVariables, ForbiddenRegisters);
    instantiateMemoryOperands(CT.ScratchSpacePointerInReg, CT.Instructions);
    return getSingleton(std::move(CT));
  }
@@ -194,7 +195,7 @@ Expected<std::vector<CodeTemplate>> ParallelSnippetGenerator::generateCodeTempla
      assert(PossibleRegisters.any() && "No register left to choose from");
      const auto RandomReg = randomBit(PossibleRegisters);
      Defs.set(RandomReg);
      IT.getValueFor(Op) = MCOperand::createReg(RandomReg);
      Variant.getValueFor(Op) = MCOperand::createReg(RandomReg);
    }
  }
  // And pick random use values that are not reserved and don't alias with defs.
@@ -206,12 +207,12 @@ Expected<std::vector<CodeTemplate>> ParallelSnippetGenerator::generateCodeTempla
      remove(PossibleRegisters, DefAliases);
      assert(PossibleRegisters.any() && "No register left to choose from");
      const auto RandomReg = randomBit(PossibleRegisters);
      IT.getValueFor(Op) = MCOperand::createReg(RandomReg);
      Variant.getValueFor(Op) = MCOperand::createReg(RandomReg);
    }
  }
  CT.Info =
      "instruction has no tied variables picking Uses different from defs";
  CT.Instructions.push_back(std::move(IT));
  CT.Instructions.push_back(std::move(Variant));
  instantiateMemoryOperands(CT.ScratchSpacePointerInReg, CT.Instructions);
  return getSingleton(std::move(CT));
}
+1 −1
Original line number Diff line number Diff line
@@ -25,7 +25,7 @@ public:
  ~ParallelSnippetGenerator() override;

  Expected<std::vector<CodeTemplate>>
  generateCodeTemplates(const Instruction &Instr,
  generateCodeTemplates(InstructionTemplate Variant,
                        const BitVector &ForbiddenRegisters) const override;

  static constexpr const size_t kMinNumDifferentAddresses = 6;
+16 −14
Original line number Diff line number Diff line
@@ -87,7 +87,7 @@ static ExecutionMode getExecutionModes(const Instruction &Instr,
}

static void appendCodeTemplates(const LLVMState &State,
                                const Instruction *Instr,
                                InstructionTemplate Variant,
                                const BitVector &ForbiddenRegisters,
                                ExecutionMode ExecutionModeBit,
                                StringRef ExecutionClassDescription,
@@ -103,7 +103,7 @@ static void appendCodeTemplates(const LLVMState &State,
    CodeTemplate CT;
    CT.Execution = ExecutionModeBit;
    CT.Info = std::string(ExecutionClassDescription);
    CT.Instructions.push_back(Instr);
    CT.Instructions.push_back(std::move(Variant));
    CodeTemplates.push_back(std::move(CT));
    return;
  }
@@ -115,27 +115,28 @@ static void appendCodeTemplates(const LLVMState &State,
  case ExecutionMode::SERIAL_VIA_EXPLICIT_REGS: {
    // Making the execution of this instruction serial by selecting one def
    // register to alias with one use register.
    const AliasingConfigurations SelfAliasing(*Instr, *Instr);
    const AliasingConfigurations SelfAliasing(Variant.getInstr(),
                                              Variant.getInstr());
    assert(!SelfAliasing.empty() && !SelfAliasing.hasImplicitAliasing() &&
           "Instr must alias itself explicitly");
    InstructionTemplate IT(Instr);
    // This is a self aliasing instruction so defs and uses are from the same
    // instance, hence twice IT in the following call.
    setRandomAliasing(SelfAliasing, IT, IT);
    // instance, hence twice Variant in the following call.
    setRandomAliasing(SelfAliasing, Variant, Variant);
    CodeTemplate CT;
    CT.Execution = ExecutionModeBit;
    CT.Info = std::string(ExecutionClassDescription);
    CT.Instructions.push_back(std::move(IT));
    CT.Instructions.push_back(std::move(Variant));
    CodeTemplates.push_back(std::move(CT));
    return;
  }
  case ExecutionMode::SERIAL_VIA_NON_MEMORY_INSTR: {
    const Instruction &Instr = Variant.getInstr();
    // Select back-to-back non-memory instruction.
    for (const auto *OtherInstr : computeAliasingInstructions(
             State, Instr, kMaxAliasingInstructions, ForbiddenRegisters)) {
      const AliasingConfigurations Forward(*Instr, *OtherInstr);
      const AliasingConfigurations Back(*OtherInstr, *Instr);
      InstructionTemplate ThisIT(Instr);
             State, &Instr, kMaxAliasingInstructions, ForbiddenRegisters)) {
      const AliasingConfigurations Forward(Instr, *OtherInstr);
      const AliasingConfigurations Back(*OtherInstr, Instr);
      InstructionTemplate ThisIT(Variant);
      InstructionTemplate OtherIT(OtherInstr);
      if (!Forward.hasImplicitAliasing())
        setRandomAliasing(Forward, ThisIT, OtherIT);
@@ -159,12 +160,13 @@ SerialSnippetGenerator::~SerialSnippetGenerator() = default;

Expected<std::vector<CodeTemplate>>
SerialSnippetGenerator::generateCodeTemplates(
    const Instruction &Instr, const BitVector &ForbiddenRegisters) const {
    InstructionTemplate Variant, const BitVector &ForbiddenRegisters) const {
  std::vector<CodeTemplate> Results;
  const ExecutionMode EM = getExecutionModes(Instr, ForbiddenRegisters);
  const ExecutionMode EM =
      getExecutionModes(Variant.getInstr(), ForbiddenRegisters);
  for (const auto EC : kExecutionClasses) {
    for (const auto ExecutionModeBit : getExecutionModeBits(EM & EC.Mask))
      appendCodeTemplates(State, &Instr, ForbiddenRegisters, ExecutionModeBit,
      appendCodeTemplates(State, Variant, ForbiddenRegisters, ExecutionModeBit,
                          EC.Description, Results);
    if (!Results.empty())
      break;
Loading